From dc11a91dc19625b318e9be7077a6f2f0b5e43d19 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 3 Mar 2011 10:21:59 +0100 Subject: [PATCH 0001/1590] Some versions of PIL throw a KeyError when reading EXIF data of certain JPEGs. See http://hg.effbot.org/pil-2009-raclette/changeset/de084654231a/ --- feincms/module/medialibrary/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 41fb499a2..b5c5e4a78 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -242,6 +242,10 @@ def save(self, *args, **kwargs): exif = image._getexif() except (AttributeError, IOError): exif = False + # PIL < 1.1.7 chokes on JPEGs with minimal EXIF data and + # throws a KeyError deep in its guts. + except KeyError: + exif = False if exif: orientation = exif.get(274) From 3c72cdbf3aea204d8fe3c61f21788446f7849f51 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 21 Jun 2011 14:33:37 +0200 Subject: [PATCH 0002/1590] Allow injecting blocks from application content templates into main template Only available with the class-based view. --- feincms/content/application/models.py | 5 +++- feincms/tests/applicationcontent_urls.py | 10 +++++++ feincms/tests/base.py | 34 ++++++++++++++++++++++++ feincms/views/cbv/views.py | 10 ++++--- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 75941147b..d4196c21e 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -282,7 +282,7 @@ def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) self.app_config = self.ALL_APPS_CONFIG.get(self.urlconf_path, {}).get('config', {}) - def process(self, request, **kwargs): + def process(self, request, **kw): page_url = self.parent.get_absolute_url() # Get the rest of the URL @@ -344,6 +344,9 @@ def process(self, request, **kwargs): for h in ('Cache-Control', 'Last-Modified', 'Expires'): if h in output: self.rendered_headers.setdefault(h, []).append(output[h]) + elif isinstance(output, tuple) and 'view' in kw: + kw['view'].template_name = output[0] + kw['view'].request._feincms_extra_context.update(output[1]) else: self.rendered_result = mark_safe(output) diff --git a/feincms/tests/applicationcontent_urls.py b/feincms/tests/applicationcontent_urls.py index 92a370b69..40574b0c7 100644 --- a/feincms/tests/applicationcontent_urls.py +++ b/feincms/tests/applicationcontent_urls.py @@ -45,6 +45,15 @@ def response(request): return HttpResponse('Anything') +def inheritance20(request): + return template.Template(''' + {% extends "base.html" %} + some content outside + {% block content %}a content {{ from_appcontent }}{% endblock %} + {% block sidebar %}b content {{ block.super }}{% block bla %}{% endblock %}{% endblock %} + '''), {'from_appcontent': 42} + + urlpatterns = patterns('', url(r'^$', module_root, name='ac_module_root'), url(r'^args_test/([^/]+)/([^/]+)/$', args_test, name='ac_args_test'), @@ -56,4 +65,5 @@ def response(request): url(r'^redirect/$', redirect), url(r'^response/$', response), url(r'^response_decorated/$', standalone(response)), + url(r'^inheritance20/$', inheritance20), ) diff --git a/feincms/tests/base.py b/feincms/tests/base.py index f05b63f46..adf6e1337 100644 --- a/feincms/tests/base.py +++ b/feincms/tests/base.py @@ -1336,6 +1336,40 @@ def test_31_sites_framework_associating_with_single_site(self): self.assertEqual(Page.objects.count(), 2) self.assertEqual(Page.objects.active().count(), 1) + def test_32_applicationcontent_inheritance20(self): + self.create_default_page_set() + + page1 = Page.objects.get(pk=1) + page1.active = True + page1.save() + + page = Page.objects.get(pk=2) + page.active = True + page.template_key = 'theother' + page.save() + + # Should not be published because the page has no application contents and should + # therefore not catch anything below it. + self.is_published(page1.get_absolute_url() + 'anything/', False) + + page.applicationcontent_set.create( + region='main', ordering=0, + urlconf_path='feincms.tests.applicationcontent_urls') + page.rawcontent_set.create( + region='main', ordering=1, text='some_main_region_text') + page.rawcontent_set.create( + region='sidebar', ordering=0, text='some_sidebar_region_text') + + self.assertContains(self.client.get(page.get_absolute_url()), + 'module_root') + + response = self.client.get(page.get_absolute_url() + 'inheritance20/') + self.assertContains(response, 'a content 42') + self.assertContains(response, 'b content') + self.assertNotContains(response, 'some_main_region_text') + self.assertContains(response, 'some_sidebar_region_text') + self.assertNotContains(response, 'some content outside') + Entry.register_extensions('seo', 'translations', 'seo', 'ct_tracker') class BlogTestCase(TestCase): diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index b6dcbb98c..005355354 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -1,4 +1,5 @@ from django.http import Http404 +from django.template import Template from django.utils.cache import add_never_cache_headers from django.views.generic import TemplateView @@ -26,9 +27,12 @@ def handler(self, request, path=None, *args, **kwargs): return self.finalize(response) def get_template_names(self): - if self.template_name is None: - return [self.page.template.path] - return [self.template_name] + # According to the documentation this method is supposed to return + # a list. However, we can also return a Template instance... + if isinstance(self.template_name, (Template, list, tuple)): + return self.template_name + + return [self.template_name or self.page.template.path] def get_context_data(self, **kwargs): context = self.request._feincms_extra_context From 49c1f981c2840779142165f085a11c1c2da5854c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 21 Jun 2011 18:22:47 +0200 Subject: [PATCH 0003/1590] Move request and response processors into their own module --- feincms/module/page/models.py | 117 ++---------------------------- feincms/module/page/processors.py | 117 ++++++++++++++++++++++++++++++ feincms/tests/base.py | 7 +- 3 files changed, 128 insertions(+), 113 deletions(-) create mode 100644 feincms/module/page/processors.py diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index e3254d171..ef090aa60 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -35,6 +35,7 @@ from feincms.admin import item_editor from feincms.management.checker import check_database_schema from feincms.models import Base, create_base_model +from feincms.module.page import processors from feincms.utils import get_object, copy_model_instance import feincms.admin.filterspecs @@ -487,119 +488,12 @@ def finalize_response(self, request, response): for fn in self.response_processors: fn(self, request, response) - def require_path_active_request_processor(self, request): - """ - Checks whether any ancestors are actually inaccessible (ie. not - inactive or expired) and raise a 404 if so. - """ - if not self.are_ancestors_active(): - raise Http404() - def get_redirect_to_target(self, request): """ This might be overriden/extended by extension modules. """ return self.redirect_to - def redirect_request_processor(self, request): - target = self.get_redirect_to_target(request) - if target: - return HttpResponseRedirect(target) - - def frontendediting_request_processor(self, request): - if not 'frontend_editing' in request.GET: - return - - if request.user.has_module_perms('page'): - try: - enable_fe = int(request.GET['frontend_editing']) > 0 - except ValueError: - enable_fe = False - - request.session['frontend_editing'] = enable_fe - - # Redirect to cleanup URLs - return HttpResponseRedirect(request.path) - - def etag_request_processor(self, request): - - # XXX is this a performance concern? Does it create a new class - # every time the processor is called or is this optimized to a static - # class?? - class DummyResponse(dict): - """ - This is a dummy class with enough behaviour of HttpResponse so we - can use the condition decorator without too much pain. - """ - def has_header(self, what): - return False - - def dummy_response_handler(*args, **kwargs): - return DummyResponse() - - def etagger(request, page, *args, **kwargs): - etag = page.etag(request) - return etag - - def lastmodifier(request, page, *args, **kwargs): - lm = page.last_modified() - return lm - - # Unavailable in Django 1.0 -- the current implementation of ETag support - # requires Django 1.1 unfortunately. - from django.views.decorators.http import condition - - # Now wrap the condition decorator around our dummy handler: - # the net effect is that we will be getting a DummyResponse from - # the handler if processing is to continue and a non-DummyResponse - # (should be a "304 not modified") if the etag matches. - rsp = condition(etag_func=etagger, last_modified_func=lastmodifier)(dummy_response_handler)(request, self) - - # If dummy then don't do anything, if a real response, return and - # thus shortcut the request processing. - if not isinstance(rsp, DummyResponse): - return rsp - - def etag_response_processor(self, request, response): - """ - Response processor to set an etag header on outgoing responses. - The Page.etag() method must return something valid as etag content - whenever you want an etag header generated. - """ - etag = self.etag(request) - if etag is not None: - response['ETag'] = '"' + etag + '"' - - @staticmethod - def debug_sql_queries_response_processor(verbose=False, file=sys.stderr): - if not django_settings.DEBUG: - return lambda self, request, response: None - - def processor(self, request, response): - from django.db import connection - - print_sql = lambda x: x - try: - import sqlparse - print_sql = lambda x: sqlparse.format(x, reindent=True, keyword_case='upper') - except: - pass - - if verbose: - print >> file, "--------------------------------------------------------------" - time = 0.0 - i = 0 - for q in connection.queries: - i += 1 - if verbose: - print >> file, "%d : [%s]\n%s\n" % ( i, q['time'], print_sql(q['sql'])) - time += float(q['time']) - - print >> file, "--------------------------------------------------------------" - print >> file, "Total: %d queries, %.3f ms" % (i, time) - print >> file, "--------------------------------------------------------------" - - return processor @classmethod def register_request_processors(cls, *processors): @@ -630,9 +524,12 @@ def register_extension(cls, register_fn): mptt.register(Page) # Our default request processors -Page.register_request_processors(Page.require_path_active_request_processor, - Page.frontendediting_request_processor, - Page.redirect_request_processor) +Page.register_request_processors(processors.require_path_active_request_processor, + processors.redirect_request_processor) + +if settings.FEINCMS_FRONTEND_EDITING: + Page.register_request_processors( + processors.frontendediting_request_processor) signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py new file mode 100644 index 000000000..cedd35f5a --- /dev/null +++ b/feincms/module/page/processors.py @@ -0,0 +1,117 @@ +import sys + +from django.conf import settings as django_settings +from django.http import Http404, HttpResponseRedirect + + +def require_path_active_request_processor(page, request): + """ + Checks whether any ancestors are actually inaccessible (ie. not + inactive or expired) and raise a 404 if so. + """ + if not page.are_ancestors_active(): + raise Http404() + + +def redirect_request_processor(page, request): + target = page.get_redirect_to_target(request) + if target: + return HttpResponseRedirect(target) + + +def frontendediting_request_processor(page, request): + if not 'frontend_editing' in request.GET: + return + + if request.user.has_module_perms('page'): + try: + enable_fe = int(request.GET['frontend_editing']) > 0 + except ValueError: + enable_fe = False + + request.session['frontend_editing'] = enable_fe + + # Redirect to cleanup URLs + return HttpResponseRedirect(request.path) + + +def etag_request_processor(page, request): + + # XXX is this a performance concern? Does it create a new class + # every time the processor is called or is this optimized to a static + # class?? + class DummyResponse(dict): + """ + This is a dummy class with enough behaviour of HttpResponse so we + can use the condition decorator without too much pain. + """ + def has_header(page, what): + return False + + def dummy_response_handler(*args, **kwargs): + return DummyResponse() + + def etagger(request, page, *args, **kwargs): + etag = page.etag(request) + return etag + + def lastmodifier(request, page, *args, **kwargs): + lm = page.last_modified() + return lm + + # Unavailable in Django 1.0 -- the current implementation of ETag support + # requires Django 1.1 unfortunately. + from django.views.decorators.http import condition + + # Now wrap the condition decorator around our dummy handler: + # the net effect is that we will be getting a DummyResponse from + # the handler if processing is to continue and a non-DummyResponse + # (should be a "304 not modified") if the etag matches. + rsp = condition(etag_func=etagger, last_modified_func=lastmodifier)(dummy_response_handler)(request, page) + + # If dummy then don't do anything, if a real response, return and + # thus shortcut the request processing. + if not isinstance(rsp, DummyResponse): + return rsp + + +def etag_response_processor(page, request, response): + """ + Response processor to set an etag header on outgoing responses. + The Page.etag() method must return something valid as etag content + whenever you want an etag header generated. + """ + etag = page.etag(request) + if etag is not None: + response['ETag'] = '"' + etag + '"' + + +def debug_sql_queries_response_processor(verbose=False, file=sys.stderr): + if not django_settings.DEBUG: + return lambda page, request, response: None + + def processor(page, request, response): + from django.db import connection + + print_sql = lambda x: x + try: + import sqlparse + print_sql = lambda x: sqlparse.format(x, reindent=True, keyword_case='upper') + except: + pass + + if verbose: + print >> file, "--------------------------------------------------------------" + time = 0.0 + i = 0 + for q in connection.queries: + i += 1 + if verbose: + print >> file, "%d : [%s]\n%s\n" % ( i, q['time'], print_sql(q['sql'])) + time += float(q['time']) + + print >> file, "--------------------------------------------------------------" + print >> file, "Total: %d queries, %.3f ms" % (i, time) + print >> file, "--------------------------------------------------------------" + + return processor diff --git a/feincms/tests/base.py b/feincms/tests/base.py index adf6e1337..1c7b2bad9 100644 --- a/feincms/tests/base.py +++ b/feincms/tests/base.py @@ -30,6 +30,7 @@ from feincms.models import Region, Template, Base, ContentProxy from feincms.module.blog.models import Entry from feincms.module.medialibrary.models import Category, MediaFile +from feincms.module.page import processors from feincms.module.page.models import Page from feincms.templatetags import feincms_tags from feincms.translations import short_language_code @@ -199,9 +200,9 @@ def test_08_creating_two_content_types_in_same_application(self): 'ct_tracker') Page.create_content_type(ContactFormContent, form=ContactForm) Page.create_content_type(FileContent) -Page.register_request_processors(Page.etag_request_processor) -Page.register_response_processors(Page.etag_response_processor) -Page.register_response_processors(Page.debug_sql_queries_response_processor()) +Page.register_request_processors(processors.etag_request_processor) +Page.register_response_processors(processors.etag_response_processor) +Page.register_response_processors(processors.debug_sql_queries_response_processor()) class PagesTestCase(TestCase): From f3da3f522e882cccd0e1b624a4fb42a4e2a72719 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 22 Jul 2011 17:19:30 +0200 Subject: [PATCH 0004/1590] FeinCMSInline can be a stock StackedInline too --- feincms/admin/item_editor.py | 4 +- feincms/static/feincms/item_editor.js | 7 ++ .../admin/feincms/content_inline.html | 106 ------------------ feincms/templatetags/feincms_admin_tags.py | 18 --- 4 files changed, 8 insertions(+), 127 deletions(-) delete mode 100644 feincms/templates/admin/feincms/content_inline.html delete mode 100644 feincms/templatetags/feincms_admin_tags.py diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index d48df6f0b..dd44a6a1d 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -15,7 +15,6 @@ from django.utils.encoding import force_unicode from django.utils.functional import curry from django.utils.translation import ugettext as _ -from django.contrib.admin.options import InlineModelAdmin from feincms import settings, ensure_completely_loaded from feincms.signals import itemeditor_post_save_related @@ -36,7 +35,7 @@ class ItemEditorForm(forms.ModelForm): ordering = forms.IntegerField(widget=forms.HiddenInput()) # ------------------------------------------------------------------------ -class FeinCMSInline(InlineModelAdmin): +class FeinCMSInline(admin.StackedInline): """ Custom ``InlineModelAdmin`` subclass used for content types. """ @@ -44,7 +43,6 @@ class FeinCMSInline(InlineModelAdmin): form = ItemEditorForm extra = 0 fk_name = 'parent' - template = 'admin/feincms/content_inline.html' # ------------------------------------------------------------------------ class ItemEditor(admin.ModelAdmin): diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index d194b9979..e6dc07883 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -269,6 +269,12 @@ if(!Array.indexOf) { contentblock_init_handlers[i](); } + function identify_feincms_inlines() { + $.each(CONTENT_NAMES, function(name, value) { + $('#' + name + '_set-group').addClass('feincms_inline'); + }); + } + function hide_form_rows_with_hidden_widgets(){ /* This is not normally done in django -- the fields are shown with visible labels and invisible widgets, but FeinCMS used to @@ -337,6 +343,7 @@ if(!Array.indexOf) { var current_template; $(document).ready(function($){ + identify_feincms_inlines(); hide_form_rows_with_hidden_widgets(); $("#main_wrapper > .navi_tab").click(function(){ diff --git a/feincms/templates/admin/feincms/content_inline.html b/feincms/templates/admin/feincms/content_inline.html deleted file mode 100644 index 267a0950d..000000000 --- a/feincms/templates/admin/feincms/content_inline.html +++ /dev/null @@ -1,106 +0,0 @@ -{% load i18n adminmedia feincms_admin_tags %} -
-

{{ inline_admin_formset.opts.verbose_name_plural|title }}

-{{ inline_admin_formset.formset.management_form }} -{{ inline_admin_formset.formset.non_form_errors }} - -{% for inline_admin_form in inline_admin_formset %}
-

{{ inline_admin_formset.opts.verbose_name|title }}: {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %}#{{ forloop.counter }}{% endif %} - {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %} - {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}{% endif %} -

- {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} - {% for fieldset in inline_admin_form %} -
- {% if fieldset.name %}

{{ fieldset.name }}

{% endif %} - {% if fieldset.description %} -
{{ fieldset.description|safe }}
- {% endif %} - {% for line in fieldset|post_process_fieldsets %} -
- {{ line.errors }} - {% for field in line %} - - {% if field.is_checkbox %} - {{ field.field }}{{ field.label_tag }} - {% else %} - {{ field.label_tag }} - {% if field.is_readonly %} -

{{ field.contents }}

- {% else %} - {{ field.field }} - {% endif %} - {% endif %} - {% if field.field.field.help_text %} -

{{ field.field.field.help_text|safe }}

- {% endif %} -
- {% endfor %} -
- {% endfor %} - - {% endfor %} - {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %} - {{ inline_admin_form.fk_field.field }} -
{% endfor %} - - - diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py deleted file mode 100644 index 04ba5e997..000000000 --- a/feincms/templatetags/feincms_admin_tags.py +++ /dev/null @@ -1,18 +0,0 @@ -from django import template - - -register = template.Library() - - -@register.filter -def post_process_fieldsets(fieldset): - """ - Removes a few fields from FeinCMS admin inlines, those being - ``id``, ``DELETE`` and ``ORDER`` currently. - """ - - excluded_fields = ('id', 'DELETE', 'ORDER') - fieldset.fields = [f for f in fieldset.form.fields.keys() if f not in excluded_fields] - - for line in fieldset: - yield line From 230274538b3abc2fba8ca01487b1e50349516b7e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sun, 24 Jul 2011 12:42:22 +0200 Subject: [PATCH 0005/1590] Activate django.contrib.staticfiles --- example/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/example/settings.py b/example/settings.py index f0d5a3e86..1c5f16399 100644 --- a/example/settings.py +++ b/example/settings.py @@ -73,6 +73,7 @@ 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.admin', + 'django.contrib.staticfiles', 'feincms', 'feincms.module.blog', From e00172919d62962a0d8dbc2e8d3025dbdd5d48a8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sun, 24 Jul 2011 12:42:53 +0200 Subject: [PATCH 0006/1590] Reorganize page fieldsets a bit, change active and in_navigation default value to True --- feincms/module/page/models.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index ef090aa60..54941b6ad 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -253,15 +253,14 @@ def from_request(self, request, best_match=False): class Page(Base): - active = models.BooleanField(_('active'), default=False) + active = models.BooleanField(_('active'), default=True) # structure and navigation - title = models.CharField(_('title'), max_length=200, - help_text=_('This is used for the generated navigation too.')) + title = models.CharField(_('title'), max_length=200) slug = models.SlugField(_('slug'), max_length=150) parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, null=True, related_name='children') parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py - in_navigation = models.BooleanField(_('in navigation'), default=False) + in_navigation = models.BooleanField(_('in navigation'), default=True) override_url = models.CharField(_('override URL'), max_length=300, blank=True, help_text=_('Override the target URL. Be sure to include slashes at the beginning and at the end if it is a local URL. This affects both the navigation and subpages\' URLs.')) redirect_to = models.CharField(_('redirect to'), max_length=300, blank=True, @@ -665,8 +664,11 @@ class Media: unknown_fields = ['override_url', 'redirect_to'] fieldsets = [ (None, { - 'fields': ['active', 'in_navigation', 'template_key', 'title', 'slug', - 'parent'], + 'fields': [ + ('title', 'slug'), + ('parent', 'active', 'in_navigation'), + 'template_key', + ], }), item_editor.FEINCMS_CONTENT_FIELDSET, (_('Other options'), { From dfc90a7617a3a6b7475f53ab1ad26837ab675034 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 26 Jul 2011 13:33:45 +0200 Subject: [PATCH 0007/1590] Deprecate the patched reverse() method in favor of an explicit solution --- feincms/content/application/models.py | 231 ++++++++++-------- .../templatetags/applicationcontent_tags.py | 88 +++++++ feincms/tests/base.py | 15 +- 3 files changed, 230 insertions(+), 104 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index d4196c21e..4fdef08a0 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -9,13 +9,10 @@ from django.core.urlresolvers import Resolver404, resolve, reverse as _reverse, NoReverseMatch from django.db import models from django.http import HttpResponse +from django.utils.functional import curry as partial, wraps from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -try: - from functools import partial -except ImportError: - from django.utils.functional import curry as partial from feincms.admin.editor import ItemEditorForm from feincms.contrib.fields import JSONField @@ -32,9 +29,14 @@ from django.utils._threading_local import local _local = local() +_local.reverse_cache = {} def retrieve_page_information(page, request=None): + """This is the request processor responsible for retrieving information + about the currently processed page so that we can make an optimal match + when reversing app URLs when the same ApplicationContent has been added + several times to the website.""" _local.proximity_info = (page.tree_id, page.lft, page.rght, page.level) @@ -42,6 +44,122 @@ def _empty_reverse_cache(): _local.reverse_cache = {} +def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, **vkwargs): + """ + Reverse URLs from application contents + + Works almost like Django's own reverse() method except that it resolves + URLs from application contents. The second argument, ``urlconf``, has to + correspond to the URLconf parameter passed in the ``APPLICATIONS`` list + to ``Page.create_content_type``:: + + app_reverse('mymodel-detail', 'myapp.urls', args=...) + + or + + app_reverse('mymodel-detail', 'myapp.urls', kwargs=...) + """ + + # vargs and vkwargs are used to send through additional parameters which are + # uninteresting to us (such as current_app) + + app_cache_keys = { + 'none': 'app_%s_none' % urlconf, + } + proximity_info = getattr(_local, 'proximity_info', None) + url_prefix = None + + if proximity_info: + app_cache_keys.update({ + 'all': 'app_%s_%s_%s_%s_%s' % ((urlconf,) + proximity_info), + 'tree': 'app_%s_%s' % (urlconf, proximity_info[0]), + }) + + for key in ('all', 'tree', 'none'): + try: + url_prefix = _local.reverse_cache[app_cache_keys[key]] + break + except (AttributeError, KeyError): + pass + else: + model_class = ApplicationContent._feincms_content_models[0] + contents = model_class.objects.filter(urlconf_path=urlconf).select_related('parent') + + if proximity_info: + # find the closest match within the same subtree + tree_contents = contents.filter(parent__tree_id=proximity_info[0]) + if not len(tree_contents): + # no application contents within the same tree + cache_key = 'tree' + try: + content = contents[0] + except IndexError: + content = None + elif len(tree_contents) == 1: + cache_key = 'tree' + # just one match within the tree, use it + content = tree_contents[0] + else: # len(tree_contents) > 1 + cache_key = 'all' + try: + # select all ancestors and descendants and get the one with + # the smallest difference in levels + content = (tree_contents.filter( + parent__rght__gt=proximity_info[2], + parent__lft__lt=proximity_info[1] + ) | tree_contents.filter( + parent__lft__lte=proximity_info[2], + parent__lft__gte=proximity_info[1], + )).extra({'level_diff':"abs(level-%d)" % proximity_info[3]} + ).order_by('level_diff')[0] + except IndexError: + content = tree_contents[0] + else: + cache_key = 'none' + try: + content = contents[0] + except IndexError: + content = None + + if content: + if urlconf in model_class.ALL_APPS_CONFIG: + # We have an overridden URLconf + urlconf = model_class.ALL_APPS_CONFIG[urlconf]['config'].get( + 'urls', urlconf) + + _local.reverse_cache[app_cache_keys[cache_key]] = url_prefix = ( + urlconf, + content.parent.get_absolute_url(), + ) + + if url_prefix: + return _reverse(viewname, + url_prefix[0], + args=args, + kwargs=kwargs, + prefix=url_prefix[1], + *vargs, **vkwargs) + raise NoReverseMatch("Unable to find ApplicationContent for '%s'" % urlconf) + + +def permalink(func): + """ + Decorator that calls app_reverse() + + Use this instead of standard django.db.models.permalink if you want to + integrate the model through ApplicationContent. The wrapped function + must return 4 instead of 3 arguments:: + + class MyModel(models.Model): + @appmodels.permalink + def get_absolute_url(self): + return ('myapp.urls', 'mymodel_detail', (), {'slug': self.slug}) + """ + def inner(*args, **kwargs): + return app_reverse(*func(*args, **kwargs)) + return wraps(func)(inner) + + APPLICATIONCONTENT_RE = re.compile(r'^([^/]+)/([^/]+)$') @@ -66,109 +184,26 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, # try to reverse an URL inside another applicationcontent other_urlconf, other_viewname = viewname.split('/') - # TODO do not use internal feincms data structures as much - model_class = ApplicationContent._feincms_content_models[0] - if hasattr(_local, 'urlconf') and other_urlconf == _local.urlconf[0]: - # We are reversing an URL from our own ApplicationContent - return _reverse(other_viewname, other_urlconf, args, kwargs, _local.urlconf[1], *vargs, **vkwargs) - - if not hasattr(_local, 'reverse_cache'): - _local.reverse_cache = {} - - - # try different cache keys of descending specificity, this one always works - urlconf_cache_keys = { - 'none': '%s_noprox' % other_urlconf, - } - - # when we have more proximity info, we can use more specific cache keys - proximity_info = getattr(_local, 'proximity_info', None) - if proximity_info: - urlconf_cache_keys.update({ - 'all': '%s_%s_%s_%s_%s' % ((other_urlconf,) + proximity_info), - 'tree': '%s_%s' % (other_urlconf, proximity_info[0]), - }) - - for key in ('all', 'tree', 'none'): - if key in urlconf_cache_keys and urlconf_cache_keys[key] in _local.reverse_cache: - content = _local.reverse_cache[urlconf_cache_keys[key]] - break - else: - contents = model_class.objects.filter( - urlconf_path=other_urlconf).select_related('parent') - - if proximity_info: - # find the closest match within the same subtree - tree_contents = contents.filter(parent__tree_id=proximity_info[0]) - if not len(tree_contents): - # no application contents within the same tree - cache_key = 'tree' - try: - content = contents[0] - except IndexError: - content = None - elif len(tree_contents) == 1: - cache_key = 'tree' - # just one match within the tree, use it - content = tree_contents[0] - else: # len(tree_contents) > 1 - cache_key = 'all' - try: - # select all ancestors and descendants and get the one with - # the smallest difference in levels - content = (tree_contents.filter( - parent__rght__gt=proximity_info[2], - parent__lft__lt=proximity_info[1] - ) | tree_contents.filter( - parent__lft__lte=proximity_info[2], - parent__lft__gte=proximity_info[1], - )).extra({'level_diff':"abs(level-%d)" % proximity_info[3]} - ).order_by('level_diff')[0] - except IndexError: - content = tree_contents[0] - else: - cache_key = 'none' - try: - content = contents[0] - except IndexError: - content = None - _local.reverse_cache[urlconf_cache_keys[cache_key]] = content + return app_reverse(other_viewname, other_urlconf, + args=args, kwargs=kwargs, prefix=prefix, *vargs, **vkwargs) - if content: - # Save information from _urlconfs in case we are inside another - # application contents' ``process`` method currently - saved_cfg = getattr(_local, 'urlconf', None) - - if other_urlconf in model_class.ALL_APPS_CONFIG: - # We have an overridden URLconf - other_urlconf = model_class.ALL_APPS_CONFIG[other_urlconf]['config'].get( - 'urls', other_urlconf) - - # Initialize application content reverse hackery for the other application - _local.urlconf = (other_urlconf, content.parent.get_absolute_url()) - - try: - url = reverse(other_viewname, other_urlconf, args, kwargs, prefix, *vargs, **vkwargs) - except: - url = None - - if saved_cfg: - _local.urlconf = saved_cfg - else: - del _local.urlconf + import warnings + warnings.warn("Reversing URLs through a patched 'django.core.urlresolvers.reverse'" + " function or using the 'urlconf/view_name' notation has been deprecated." + " Use 'feincms.content.application.models.app_reverse' or the 'app_reverse'" + " template tag from 'applicationcontent_tags' directly.", + DeprecationWarning) - # We found an URL somewhere in here... return it. Otherwise, we continue - # below - if url: - return url + return app_reverse(other_viewname, other_urlconf, + args=args, kwargs=kwargs, prefix=prefix, *vargs, **vkwargs) if hasattr(_local, 'urlconf'): # Special handling inside ApplicationContent.render; override urlconf # and prefix variables so that reverse works as expected. urlconf1, prefix1 = _local.urlconf try: - return _reverse(viewname, urlconf1, args, kwargs, prefix1, *vargs, **vkwargs) + return app_reverse(viewname, urlconf1, args, kwargs, prefix1, *vargs, **vkwargs) except NoReverseMatch: # fall through to calling reverse with default arguments pass diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index d13cd2877..fa2f23986 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -1,4 +1,6 @@ from django import template +from django.core.urlresolvers import NoReverseMatch +from django.template.defaulttags import kwarg_re # backwards compatibility import from feincms.templatetags.fragment_tags import fragment, get_fragment, has_fragment @@ -29,3 +31,89 @@ def feincms_render_region_appcontent(page, region, request): return u''.join(_render_content(content, request=request) for content in\ page.content.all_of_type(ApplicationContent) if content.region == region) + + +class AppReverseNode(template.Node): + def __init__(self, view_name, urlconf, args, kwargs, asvar): + self.view_name = view_name + self.urlconf = urlconf + self.args = args + self.kwargs = kwargs + self.asvar = asvar + + def render(self, context): + from feincms.content.application.models import app_reverse + + args = [arg.resolve(context) for arg in self.args] + kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context)) + for k, v in self.kwargs.items()]) + view_name = self.view_name.resolve(context) + urlconf = self.urlconf.resolve(context) + + try: + url = app_reverse(view_name, urlconf, args=args, kwargs=kwargs, + current_app=context.current_app) + except NoReverseMatch: + if self.asvar is None: + raise + + if self.asvar: + context[self.asvar] = url + return u'' + else: + return url + + +@register.tag +def app_reverse(parser, token): + """ + Returns an absolute URL for applications integrated with ApplicationContent + + The tag mostly works the same way as Django's own {% url %} tag:: + + {% load applicationcontent_tags %} + {% app_reverse "mymodel_detail" "myapp.urls" arg1 arg2 %} + + or + + {% load applicationcontent_tags %} + {% app_reverse "mymodel_detail" "myapp.urls" name1=value1 name2=value2 %} + + The first argument is a path to a view. The second argument is the URLconf + under which this app is known to the ApplicationContent. + + Other arguments are space-separated values that will be filled in place of + positional and keyword arguments in the URL. Don't mix positional and + keyword arguments. + + If you want to store the URL in a variable instead of showing it right away + you can do so too:: + + {% app_reverse "mymodel_detail" "myapp.urls" arg1 arg2 as url %} + """ + bits = token.split_contents() + if len(bits) < 3: + raise TemplateSyntaxError("'%s' takes at least two arguments" + " (path to a view and a urlconf)" % bits[0]) + viewname = parser.compile_filter(bits[1]) + urlconf = parser.compile_filter(bits[2]) + args = [] + kwargs = {} + asvar = None + bits = bits[3:] + if len(bits) >= 3 and bits[-2] == 'as': + asvar = bits[-1] + bits = bits[:-2] + + if len(bits): + for bit in bits: + match = kwarg_re.match(bit) + if not match: + raise TemplateSyntaxError("Malformed arguments to app_reverse tag") + name, value = match.groups() + if name: + kwargs[name] = parser.compile_filter(value) + else: + args.append(parser.compile_filter(value)) + + return AppReverseNode(viewname, urlconf, args, kwargs, asvar) diff --git a/feincms/tests/base.py b/feincms/tests/base.py index 1c7b2bad9..dd26aa3f9 100644 --- a/feincms/tests/base.py +++ b/feincms/tests/base.py @@ -1241,12 +1241,15 @@ def test_28_applicationcontent_reverse(self): region='main', ordering=0, urlconf_path='feincms.tests.applicationcontent_urls') - from django.core.urlresolvers import reverse + from feincms.content.application.models import app_reverse, reverse - # test reverse replacement - self.assertEqual(reverse('feincms.tests.applicationcontent_urls/ac_module_root'), + # test app_reverse + self.assertEqual(app_reverse('ac_module_root', 'feincms.tests.applicationcontent_urls'), page.get_absolute_url()) + # test reverse replacement - should still work, but is deprecated + self.assertEqual(reverse('feincms.tests.applicationcontent_urls/ac_module_root'), + page.get_absolute_url()) # when specific applicationcontent exists more then once reverse should return url # for the one that has tree_id same as current feincms page @@ -1260,12 +1263,12 @@ def test_28_applicationcontent_reverse(self): _empty_reverse_cache() settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), 'templates'),) - self.client.get(page_de.get_absolute_url()) - self.assertEqual(reverse('feincms.tests.applicationcontent_urls/ac_module_root'), + self.client.get(page_de_1.get_absolute_url()) + self.assertEqual(app_reverse('ac_module_root', 'feincms.tests.applicationcontent_urls'), page_de_1.get_absolute_url()) self.client.get(page1.get_absolute_url()) - self.assertEqual(reverse('feincms.tests.applicationcontent_urls/ac_module_root'), + self.assertEqual(app_reverse('ac_module_root', 'feincms.tests.applicationcontent_urls'), page.get_absolute_url()) def test_29_medialibrary_admin(self): From a918ef088bf3dc27ed861391490fc1e0160cdba1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 26 Jul 2011 16:33:11 +0200 Subject: [PATCH 0008/1590] Be a bit more careful when accessing reverse_cache --- feincms/content/application/models.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 4fdef08a0..9acce953e 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -28,8 +28,10 @@ except ImportError: from django.utils._threading_local import local -_local = local() -_local.reverse_cache = {} +_local = local() # Used to store MPTT informations about the currently requested + # page. The information will be used to find the best application + # content instance if a particular application has been added + # more than once to the current website. def retrieve_page_information(page, request=None): @@ -83,6 +85,8 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, pass else: model_class = ApplicationContent._feincms_content_models[0] + + # TODO: Only active pages? What about multisite support? contents = model_class.objects.filter(urlconf_path=urlconf).select_related('parent') if proximity_info: @@ -127,6 +131,9 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, urlconf = model_class.ALL_APPS_CONFIG[urlconf]['config'].get( 'urls', urlconf) + if not hasattr(_local, 'reverse_cache'): + _local.reverse_cache = {} + _local.reverse_cache[app_cache_keys[cache_key]] = url_prefix = ( urlconf, content.parent.get_absolute_url(), From 88310f04e7813f95490df93b21ca676bb3f78208 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 26 Jul 2011 19:55:36 +0200 Subject: [PATCH 0009/1590] Add missing import --- feincms/templatetags/applicationcontent_tags.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index fa2f23986..e6ff42852 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -1,6 +1,7 @@ from django import template from django.core.urlresolvers import NoReverseMatch from django.template.defaulttags import kwarg_re +from django.utils.encoding import smart_str # backwards compatibility import from feincms.templatetags.fragment_tags import fragment, get_fragment, has_fragment From 05f122ec2c2e0b369d3c41df9758c7616a4300b0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 28 Jul 2011 14:05:55 +0200 Subject: [PATCH 0010/1590] Fix infinite reverse / app_reverse recursion case Removing the reverse() monkey patch seems like a really really good idea now. --- feincms/content/application/models.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 9acce953e..a716b0197 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -134,10 +134,17 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, if not hasattr(_local, 'reverse_cache'): _local.reverse_cache = {} + # Reimplementation of Page.get_absolute_url because we are quite likely + # to hit infinite recursion if we call models.permalink because of the + # reverse monkey patch + url = content.parent._cached_url[1:-1] + if url: + prefix = _reverse('feincms_handler', args=(url,)) + else: + prefix = _reverse('feincms_home') + _local.reverse_cache[app_cache_keys[cache_key]] = url_prefix = ( - urlconf, - content.parent.get_absolute_url(), - ) + urlconf, prefix) if url_prefix: return _reverse(viewname, From 4c323f0d9ef6cf1d162f950aa27181b1613ee995 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 28 Jul 2011 14:10:45 +0200 Subject: [PATCH 0011/1590] Allow deactivating the reverse() monkey patch with a setting --- feincms/content/application/models.py | 6 ++++-- feincms/default_settings.py | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index a716b0197..d73a1c458 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -13,7 +13,7 @@ from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ - +from feincms import settings from feincms.admin.editor import ItemEditorForm from feincms.contrib.fields import JSONField from feincms.utils import get_object @@ -223,7 +223,9 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, pass return _reverse(viewname, urlconf, args, kwargs, prefix, *vargs, **vkwargs) -urlresolvers.reverse = reverse + +if settings.FEINCMS_REVERSE_MONKEY_PATCH: + urlresolvers.reverse = reverse class ApplicationContent(models.Model): diff --git a/feincms/default_settings.py b/feincms/default_settings.py index e43b84494..7bcfe1ea8 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -98,3 +98,11 @@ FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE = getattr(settings, 'FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE', True) #: Name of the tidy function - anything which takes (html) and returns (html, errors, warnings) can be used: FEINCMS_TIDY_FUNCTION = getattr(settings, 'FEINCMS_TIDY_FUNCTION', 'feincms.utils.html.tidy.tidy_html') + + +# ------------------------------------------------------------------------ +#: Monkey-patch django.core.urlresvolers.reverse to be application-content aware? +#: (The monkey patch is deprecated and should not be used anymore. Use the +#: ``app_reverse`` function and the ``{% app_reverse %}`` template tag instead.) +#: The value of this setting will be changed to False in FeinCMS 1.6. +FEINCMS_REVERSE_MONKEY_PATCH = getattr(settings, 'FEINCMS_REVERSE_MONKEY_PATCH', True) From ddda7c583bf1d1c6ef6a2b8e1452d8e8d680cb2a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 07:21:00 +0200 Subject: [PATCH 0012/1590] Stop supporting django-mptt versions older than 0.4 --- example/models.py | 14 +++----------- feincms/admin/tree_editor.py | 5 +---- feincms/module/page/extensions/navigation.py | 3 --- feincms/module/page/models.py | 17 ++--------------- 4 files changed, 6 insertions(+), 33 deletions(-) diff --git a/example/models.py b/example/models.py index db3954216..4eb8d1b1c 100644 --- a/example/models.py +++ b/example/models.py @@ -3,6 +3,8 @@ from django.utils.text import capfirst from django.utils.translation import ugettext_lazy as _ +from mptt.models import MPTTModel + from feincms.module.blog.models import Entry, EntryAdmin from feincms.module.page.models import Page from feincms.content.raw.models import RawContent @@ -12,8 +14,6 @@ from feincms.module.page.extensions.navigation import NavigationExtension, PagePretender from feincms.content.application.models import reverse -import mptt - Page.register_templates({ 'key': 'base', @@ -74,14 +74,8 @@ def children(self, page, **kwargs): Page.register_extensions('sites') -try: - from mptt.models import MPTTModel as base - mptt_register = False -except ImportError: - base = models.Model - mptt_register = True -class Category(base): +class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() parent = models.ForeignKey('self', blank=True, null=True, related_name='children') @@ -94,8 +88,6 @@ class Meta: def __unicode__(self): return self.name -if mptt_register: - mptt.register(Category) # add m2m field to entry so it shows up in entry admin Entry.add_to_class('categories', models.ManyToManyField(Category, blank=True, null=True)) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index b0700447d..c1c62010d 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -46,10 +46,7 @@ def _build_tree_structure(cls): """ all_nodes = { } - if hasattr(cls, '_mptt_meta'): # New-style MPTT - mptt_opts = cls._mptt_meta - else: - mptt_opts = cls._meta + mptt_opts = cls._mptt_meta for p_id, parent_id in cls.objects.order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr).values_list("pk", "%s_id" % mptt_opts.parent_attr): all_nodes[p_id] = [] diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 153ccd38b..7397ec895 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -37,9 +37,6 @@ class PagePretender(object): also add language. """ # emulate mptt properties to get the template tags working - class _meta: - level_attr = 'level' - class _mptt_meta: level_attr = 'level' diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 54941b6ad..c21494a56 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -28,7 +28,7 @@ from django.utils.translation import ugettext_lazy as _, ugettext from django.db.transaction import commit_on_success -import mptt +from mptt.models import MPTTModel from feincms import settings, ensure_completely_loaded from feincms.admin import editor @@ -242,17 +242,7 @@ def from_request(self, request, best_match=False): # MARK: - # ------------------------------------------------------------------------ -try: - # MPTT 0.4 - from mptt.models import MPTTModel - mptt_register = False - Base = create_base_model(MPTTModel) -except ImportError: - # MPTT 0.3 - mptt_register = True - - -class Page(Base): +class Page(create_base_model(MPTTModel)): active = models.BooleanField(_('active'), default=True) # structure and navigation @@ -519,9 +509,6 @@ def register_extension(cls, register_fn): # ------------------------------------------------------------------------ -if mptt_register: # MPTT 0.3 legacy support - mptt.register(Page) - # Our default request processors Page.register_request_processors(processors.require_path_active_request_processor, processors.redirect_request_processor) From 5fcb47b7a25feb562bab2a25cc8ecbb1e9089f7f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 07:27:53 +0200 Subject: [PATCH 0013/1590] Make the switch to using the class-based Django 1.3-only views by default --- feincms/urls.py | 5 +- feincms/views/base.py | 114 ++----------------------------- feincms/views/cbv/urls.py | 2 +- feincms/views/legacy/__init__.py | 0 feincms/views/legacy/base.py | 109 +++++++++++++++++++++++++++++ feincms/views/legacy/urls.py | 8 +++ 6 files changed, 127 insertions(+), 111 deletions(-) create mode 100644 feincms/views/legacy/__init__.py create mode 100644 feincms/views/legacy/base.py create mode 100644 feincms/views/legacy/urls.py diff --git a/feincms/urls.py b/feincms/urls.py index aca579814..45cc0f818 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -1,6 +1,7 @@ -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, include, url -from feincms.views.base import handler +from feincms.views.cbv.views import Handler +handler = Handler.as_view() urlpatterns = patterns('', url(r'^$', handler, name='feincms_home'), diff --git a/feincms/views/base.py b/feincms/views/base.py index c7975543a..e4345efd9 100644 --- a/feincms/views/base.py +++ b/feincms/views/base.py @@ -1,109 +1,7 @@ -from django.http import Http404 -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.utils.cache import add_never_cache_headers +import warnings +warnings.warning('feincms.views.base is deprecated. Please use feincms.views.legacy if ' + 'you want to keep on using the old handler. Otherwise, it is advised to switch ' + 'to the class-based view (Django >= 1.3 only).', + DeprecationWarning) -from feincms import settings -from feincms.module.page.models import Page - - -class Handler(object): - """ - This is the default handler for feincms page content. - - It isn't a class-based-view like those in Django's generic view framework. - State should not be stored on the ``Handler`` class, because of thread-safety - and cross polination issues. - """ - - def __call__(self, request, path=None): - return self.build_response(request, - Page.objects.best_match_for_path(path or request.path, raise404=True)) - - def build_response(self, request, page): - """ - Calls `prepare`, `render` and `finalize`, in this order. - """ - - response = self.prepare(request, page) - if response: - return response - - response = self.render(request, page) - return self.finalize(request, response, page) - - def prepare(self, request, page): - """ - Prepare / pre-process content types. If this method returns anything, - it is treated as a ``HttpResponse`` and handed back to the visitor. - """ - - response = page.setup_request(request) - if response: - return response - - http404 = None # store eventual Http404 exceptions for re-raising, - # if no content type wants to handle the current request - successful = False # did any content type successfully end processing? - - for content in page.content.all_of_type(tuple(page._feincms_content_types_with_process)): - try: - r = content.process(request) - if r in (True, False): - successful = r - elif r: - return r - except Http404, e: - http404 = e - - if not successful: - if http404: - # re-raise stored Http404 exception - raise http404 - - if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ - request._feincms_extra_context['extra_path'] != '/': - raise Http404 - - def render(self, request, page): - """ - The render step. Must return a HttpResponse. - """ - - # This facility can be used by request processors to add values - # to the context. - context = request._feincms_extra_context - context['feincms_page'] = page - - return render_to_response(page.template.path, - context_instance=RequestContext(request, context)) - - def finalize(self, request, response, page): - """ - Runs finalize() on content types having such a method, adds headers and - returns the final response. - """ - - for content in page.content.all_of_type(tuple(page._feincms_content_types_with_finalize)): - r = content.finalize(request, response) - if r: - return r - - page.finalize_response(request, response) - - # Add never cache headers in case frontend editing is active - if hasattr(request, "session") and request.session.get('frontend_editing', False): - add_never_cache_headers(response) - - return response - - @property - def __name__(self): - """ - Dummy property to make this handler behave like a normal function. - This property is used by django-debug-toolbar - """ - return self.__class__.__name__ - -#: Default handler -handler = Handler() +from feincms.views.legacy.views import * diff --git a/feincms/views/cbv/urls.py b/feincms/views/cbv/urls.py index cf7ff95c1..45cc0f818 100644 --- a/feincms/views/cbv/urls.py +++ b/feincms/views/cbv/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, include, url from feincms.views.cbv.views import Handler handler = Handler.as_view() diff --git a/feincms/views/legacy/__init__.py b/feincms/views/legacy/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/feincms/views/legacy/base.py b/feincms/views/legacy/base.py new file mode 100644 index 000000000..d9a700262 --- /dev/null +++ b/feincms/views/legacy/base.py @@ -0,0 +1,109 @@ +from django.http import Http404 +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.utils.cache import add_never_cache_headers + +from feincms import settings +from feincms.module.page.models import Page + + +class Handler(object): + """ + This is the legacy handler for feincms page content. + + It isn't a class-based-view like those in Django's generic view framework. + State should not be stored on the ``Handler`` class, because of thread-safety + and cross polination issues. + """ + + def __call__(self, request, path=None): + return self.build_response(request, + Page.objects.best_match_for_path(path or request.path, raise404=True)) + + def build_response(self, request, page): + """ + Calls `prepare`, `render` and `finalize`, in this order. + """ + + response = self.prepare(request, page) + if response: + return response + + response = self.render(request, page) + return self.finalize(request, response, page) + + def prepare(self, request, page): + """ + Prepare / pre-process content types. If this method returns anything, + it is treated as a ``HttpResponse`` and handed back to the visitor. + """ + + response = page.setup_request(request) + if response: + return response + + http404 = None # store eventual Http404 exceptions for re-raising, + # if no content type wants to handle the current request + successful = False # did any content type successfully end processing? + + for content in page.content.all_of_type(tuple(page._feincms_content_types_with_process)): + try: + r = content.process(request) + if r in (True, False): + successful = r + elif r: + return r + except Http404, e: + http404 = e + + if not successful: + if http404: + # re-raise stored Http404 exception + raise http404 + + if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ + request._feincms_extra_context['extra_path'] != '/': + raise Http404 + + def render(self, request, page): + """ + The render step. Must return a HttpResponse. + """ + + # This facility can be used by request processors to add values + # to the context. + context = request._feincms_extra_context + context['feincms_page'] = page + + return render_to_response(page.template.path, + context_instance=RequestContext(request, context)) + + def finalize(self, request, response, page): + """ + Runs finalize() on content types having such a method, adds headers and + returns the final response. + """ + + for content in page.content.all_of_type(tuple(page._feincms_content_types_with_finalize)): + r = content.finalize(request, response) + if r: + return r + + page.finalize_response(request, response) + + # Add never cache headers in case frontend editing is active + if hasattr(request, "session") and request.session.get('frontend_editing', False): + add_never_cache_headers(response) + + return response + + @property + def __name__(self): + """ + Dummy property to make this handler behave like a normal function. + This property is used by django-debug-toolbar + """ + return self.__class__.__name__ + +#: Default handler +handler = Handler() diff --git a/feincms/views/legacy/urls.py b/feincms/views/legacy/urls.py new file mode 100644 index 000000000..09e607151 --- /dev/null +++ b/feincms/views/legacy/urls.py @@ -0,0 +1,8 @@ +from django.conf.urls.defaults import patterns, include, url + +from feincms.views.legacy.views import handler + +urlpatterns = patterns('', + url(r'^$', handler, name='feincms_home'), + url(r'^(.*)/$', handler, name='feincms_handler'), +) From 890a15e0b70932b1d42d5504387bf1c99bfa4b0f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 07:30:31 +0200 Subject: [PATCH 0014/1590] Remove the legacy filterspecs support --- feincms/admin/filterspecs.py | 39 ++++++++---------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index 872960f3a..0694eec0d 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -4,15 +4,7 @@ # Authors: Marinho Brandao # Guilherme M. Gondim (semente) -try: - from django.contrib.admin.filters import FieldListFilter, ChoicesFieldListFilter - legacy = False -except ImportError: # Django up to 1.3 - from django.contrib.admin.filterspecs import ( - FilterSpec as FieldListFilter, - ChoicesFilterSpec as ChoicesFieldListFilter) - legacy = True - +from django.contrib.admin.filters import FieldListFilter, ChoicesFieldListFilter from django.utils.encoding import smart_unicode from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ @@ -29,12 +21,7 @@ class ParentFieldListFilter(ChoicesFieldListFilter): def __init__(self, f, request, params, model, model_admin, field_path=None): from feincms.utils import shorten_string - - try: - super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin, field_path) - except TypeError: # Django 1.2 - super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin) - + super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin, field_path) parent_ids = model.objects.exclude(parent=None).values_list("parent__id", flat=True).order_by("parent__id").distinct() parents = model.objects.filter(pk__in=parent_ids).values_list("pk", "title", "level") self.lookup_choices = [(pk, "%s%s" % (" " * level, shorten_string(title, max_length=25))) for pk, title, level in parents] @@ -95,19 +82,9 @@ def title(self): return _('Category') -if legacy: - # registering the filter - FieldListFilter.filter_specs.insert(0, - (lambda f: getattr(f, 'parent_filter', False), ParentFieldListFilter) - ) - - FieldListFilter.filter_specs.insert(1, - (lambda f: getattr(f, 'category_filter', False), CategoryFieldListFilter) - ) -else: - FieldListFilter.register(lambda f: getattr(f, 'parent_filter', False), - ParentFieldListFilter, - take_priority=True) - FieldListFilter.register(lambda f: getattr(f, 'category_filter', False), - CategoryFieldListFilter, - take_priority=True) +FieldListFilter.register(lambda f: getattr(f, 'parent_filter', False), + ParentFieldListFilter, + take_priority=True) +FieldListFilter.register(lambda f: getattr(f, 'category_filter', False), + CategoryFieldListFilter, + take_priority=True) From 02d2c378a9948830c23162b7c022ac6012a0d9b7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 07:46:03 +0200 Subject: [PATCH 0015/1590] Make request and response processors accessible in the old location --- feincms/module/page/models.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c21494a56..d4a657c2a 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -242,6 +242,28 @@ def from_request(self, request, best_match=False): # MARK: - # ------------------------------------------------------------------------ +class _LegacyProcessorDescriptor(object): + """ + Request and response processors have been moved into their own module; + this descriptor allows accessing them the old way (as attributes of the + Page class) but emits a warning. This class will only be available during + the FeinCMS 1.5 lifecycle. + """ + def __init__(self, name): + self.name = name + + def __get__(self, obj, objtype=None): + warnings.warn('Page request and response processors have been moved into ' + 'their own module. Accessing them via the Page class will not be possible ' + 'in FeinCMS 1.6 anymore.', + DeprecationWarning) + return getattr(processors, self.name) + + def __set__(self, obj, val): + setattr(processors, self.name, val) + +# ------------------------------------------------------------------------ + class Page(create_base_model(MPTTModel)): active = models.BooleanField(_('active'), default=True) @@ -507,6 +529,19 @@ def register_response_processors(cls, *processors): def register_extension(cls, register_fn): register_fn(cls, PageAdmin) + require_path_active_request_processor = _LegacyProcessorDescriptor( + 'require_path_active_request_processor') + redirect_request_processor = _LegacyProcessorDescriptor( + 'redirect_request_processor') + frontendediting_request_processor = _LegacyProcessorDescriptor( + 'frontendediting_request_processor') + etag_request_processor = _LegacyProcessorDescriptor( + 'etag_request_processor') + etag_response_processor = _LegacyProcessorDescriptor( + 'etag_response_processor') + debug_sql_queries_response_processor = _LegacyProcessorDescriptor( + 'debug_sql_queries_response_processor') + # ------------------------------------------------------------------------ # Our default request processors From 68e36c323cfb86848e18c6059734ca10a23b0e67 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 09:02:09 +0200 Subject: [PATCH 0016/1590] Simplify example urls.py file Much is not necessary now that we only support 1.3 (in this branch). --- example/urls.py | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/example/urls.py b/example/urls.py index b25d6d764..90e114b27 100644 --- a/example/urls.py +++ b/example/urls.py @@ -1,40 +1,15 @@ import os from django.conf.urls.defaults import * - from django.contrib import admin +from django.contrib.staticfiles.urls import staticfiles_urlpatterns + admin.autodiscover() urlpatterns = patterns('', - # Example: - # (r'^example/', include('example.foo.urls')), - - # This avoids breaking Django admin's localization JavaScript when using - # the FeinCMS frontend editing: - url(r'admin/page/page/jsi18n/', 'django.views.generic.simple.redirect_to', {'url': '/admin/jsi18n/'}), - - # Uncomment the admin/doc line below and add 'django.contrib.admindocs' - # to INSTALLED_APPS to enable admin documentation: - # (r'^admin/doc/', include('django.contrib.admindocs.urls')), - - #(r'^admin/', include(admin.site.urls)), - (r'^admin/', include(admin.site.urls) ), - - (r'^feincms_media/(?P.*)$', 'django.views.static.serve', - {'document_root': os.path.join(os.path.dirname(os.path.dirname(__file__)), 'feincms/static/feincms/')}), - - (r'^media/(?P.*)$', 'django.views.static.serve', + url(r'^admin/', include(admin.site.urls) ), + url(r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': os.path.join(os.path.dirname(__file__), 'media/')}), -) - -import django -if django.VERSION > (1, 3): - urlpatterns += patterns('', (r'', include('feincms.views.cbv.urls'))) -else: - urlpatterns += patterns('', (r'', include('feincms.urls'))) + url(r'', include('feincms.urls')) +) + staticfiles_urlpatterns() -try: - from django.contrib.staticfiles.urls import staticfiles_urlpatterns - urlpatterns += staticfiles_urlpatterns() -except ImportError: - pass From 114c4d0c6f211dff99649e4148be41a455e841c3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 10:03:31 +0200 Subject: [PATCH 0017/1590] Convert everything to staticfiles now that we support Django 1.3 upwards only --- docs/installation.rst | 8 +------ docs/page.rst | 3 +-- feincms/admin/item_editor.py | 6 ------ feincms/admin/tree_editor.py | 2 -- feincms/default_settings.py | 4 ---- .../templates/admin/content/table/init.html | 2 +- .../templates/admin/feincms/_regions_js.html | 2 +- .../templates/admin/feincms/fe_editor.html | 14 ++++--------- .../admin/feincms/fe_editor_done.html | 11 +++------- feincms/templates/admin/feincms/fe_tools.html | 6 +++--- .../templates/admin/feincms/item_editor.html | 15 +++++-------- .../templates/admin/feincms/tree_editor.html | 21 +++++++------------ feincms/templatetags/feincms_tags.py | 2 -- 13 files changed, 27 insertions(+), 69 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 2257f8a16..6263e1ba6 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -47,13 +47,7 @@ There isn't much left to do apart from adding ``feincms`` to ``INSTALLED_APPS``. The customized administration interface needs some media and javascript libraries which you have to make available to the browser. If you use Django 1.3's ``django.contrib.staticfiles`` application, the media files will be picked up -automatically by the ``collectstatic`` management command. If you use ``/static/`` -as ``STATIC_URL``, all is fine. Otherwise you have to set ``FEINCMS_ADMIN_MEDIA`` -to the path where the FeinCMS media files can be found. - -If you use an older version of Django, publish the files in the folder -``feincms/static/feincms/`` somewhere on your site and set ``FEINCMS_ADMIN_MEDIA`` -to the location. +automatically by the ``collectstatic`` management command. Please note that the ``feincms`` module will not create or need any database tables, but you need to put it into ``INSTALLED_APPS`` because otherwise the diff --git a/docs/page.rst b/docs/page.rst index 3842763e3..03636e746 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -75,8 +75,7 @@ Setting up the admin interface ============================== The customized admin interface code is contained inside the :class:`ModelAdmin` -subclass, so you do not need to do anything special here. You only need to set -:data:`~feincms.settings.FEINCMS_ADMIN_MEDIA` as described in the installation documentation. +subclass, so you do not need to do anything special here. If you use the :class:`~feincms.content.richtext.models.RichTextContent`, you need to download `TinyMCE `_ and configure FeinCMS' diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index dd44a6a1d..02f90a5de 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -135,9 +135,6 @@ def _frontend_editing_view(self, request, cms_id, content_type, content_id): return render_to_response('admin/feincms/fe_editor_done.html', { 'content': obj.render(request=request), 'identifier': obj.fe_identifier(), - 'FEINCMS_ADMIN_MEDIA': settings.FEINCMS_ADMIN_MEDIA, - 'FEINCMS_ADMIN_MEDIA_HOTLINKING': \ - settings.FEINCMS_ADMIN_MEDIA_HOTLINKING, 'FEINCMS_JQUERY_NO_CONFLICT': \ settings.FEINCMS_JQUERY_NO_CONFLICT, }) @@ -174,9 +171,6 @@ def get_extra_context(self, request): getattr(self.model, '_feincms_templates', ()), 'has_parent_attribute': hasattr(self.model, 'parent'), 'content_types': self.get_content_type_map(), - 'FEINCMS_ADMIN_MEDIA': settings.FEINCMS_ADMIN_MEDIA, - 'FEINCMS_ADMIN_MEDIA_HOTLINKING': - settings.FEINCMS_ADMIN_MEDIA_HOTLINKING, 'FEINCMS_JQUERY_NO_CONFLICT': settings.FEINCMS_JQUERY_NO_CONFLICT, 'FEINCMS_CONTENT_FIELDSET_NAME': FEINCMS_CONTENT_FIELDSET_NAME, diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index c1c62010d..7b2766a2d 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -341,8 +341,6 @@ def changelist_view(self, request, extra_context=None, *args, **kwargs): self._refresh_changelist_caches() extra_context = extra_context or {} - extra_context['FEINCMS_ADMIN_MEDIA'] = settings.FEINCMS_ADMIN_MEDIA - extra_context['FEINCMS_ADMIN_MEDIA_HOTLINKING'] = settings.FEINCMS_ADMIN_MEDIA_HOTLINKING extra_context['tree_structure'] = mark_safe(simplejson.dumps( _build_tree_structure(self.model))) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 7bcfe1ea8..f2d1fd0f1 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -34,10 +34,6 @@ # ------------------------------------------------------------------------ # Admin media settings -#: Path to FeinCMS' admin media -FEINCMS_ADMIN_MEDIA = getattr(settings, 'FEINCMS_ADMIN_MEDIA', '/static/feincms/') -#: Link to google APIs instead of using local copy of JS libraries -FEINCMS_ADMIN_MEDIA_HOTLINKING = getattr(settings, 'FEINCMS_ADMIN_MEDIA_HOTLINKING', False) #: avoid jQuery conflicts -- scripts should use feincms.jQuery instead of $ FEINCMS_JQUERY_NO_CONFLICT = \ getattr(settings, 'FEINCMS_JQUERY_NO_CONFLICT', False) diff --git a/feincms/templates/admin/content/table/init.html b/feincms/templates/admin/content/table/init.html index f9734ac81..27978f63a 100644 --- a/feincms/templates/admin/content/table/init.html +++ b/feincms/templates/admin/content/table/init.html @@ -1,5 +1,5 @@ {% load adminmedia i18n %} - + - -{% else %} - - -{% endif %} - - + + + - + {% include "admin/feincms/_messages_js.html" %} {% include "admin/feincms/_regions_js.html" %} diff --git a/feincms/templates/admin/feincms/fe_editor_done.html b/feincms/templates/admin/feincms/fe_editor_done.html index 24d9c2fd8..74ba14a8f 100644 --- a/feincms/templates/admin/feincms/fe_editor_done.html +++ b/feincms/templates/admin/feincms/fe_editor_done.html @@ -1,11 +1,6 @@ -{% if FEINCMS_ADMIN_MEDIA_HOTLINKING %} - - -{% else %} - - -{% endif %} - + + + - - + +
{% trans "Stop Editing" %} diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index 6a4764c0b..bed8a7993 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -3,17 +3,12 @@ {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} -{% if FEINCMS_ADMIN_MEDIA_HOTLINKING %} - - -{% else %} - - -{% endif %} + + {% endblock %} - - + + - + {% include "admin/feincms/_messages_js.html" %} {% include "admin/feincms/_regions_js.html" %} diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index 35f3bfa58..294753a98 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -3,16 +3,11 @@ {% block extrahead %} {{ block.super }} - - + + -{% if FEINCMS_ADMIN_MEDIA_HOTLINKING %} - - -{% else %} - - -{% endif %} + + - - - - + + + + {% endblock %} diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index bd3cd8898..3f949d173 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -105,8 +105,6 @@ def feincms_frontend_editing(cms_obj, request): if hasattr(request, 'session') and request.session.get('frontend_editing'): context = template.RequestContext(request, { "feincms_page": cms_obj, - 'FEINCMS_ADMIN_MEDIA': feincms_settings.FEINCMS_ADMIN_MEDIA, - 'FEINCMS_ADMIN_MEDIA_HOTLINKING': feincms_settings.FEINCMS_ADMIN_MEDIA_HOTLINKING }) return render_to_string('admin/feincms/fe_tools.html', context) From a66cff7d14991d211856fa6282994ede65759bc4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 10:13:52 +0200 Subject: [PATCH 0018/1590] Fix a few blunders --- feincms/views/base.py | 2 +- feincms/views/legacy/{base.py => views.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename feincms/views/legacy/{base.py => views.py} (100%) diff --git a/feincms/views/base.py b/feincms/views/base.py index e4345efd9..e1c4737f6 100644 --- a/feincms/views/base.py +++ b/feincms/views/base.py @@ -1,5 +1,5 @@ import warnings -warnings.warning('feincms.views.base is deprecated. Please use feincms.views.legacy if ' +warnings.warn('feincms.views.base is deprecated. Please use feincms.views.legacy if ' 'you want to keep on using the old handler. Otherwise, it is advised to switch ' 'to the class-based view (Django >= 1.3 only).', DeprecationWarning) diff --git a/feincms/views/legacy/base.py b/feincms/views/legacy/views.py similarity index 100% rename from feincms/views/legacy/base.py rename to feincms/views/legacy/views.py From e890850d0765471da4813656a5bd8fd36fe105d7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 10:17:32 +0200 Subject: [PATCH 0019/1590] Use the class-based view for previews too --- feincms/contrib/preview/views.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 5abf2b2b0..7727a9e6a 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -3,7 +3,7 @@ from feincms.module.page import processors from feincms.module.page.models import Page -from feincms.views.base import Handler +from feincms.views.cbv.views import Handler class PreviewHandler(Handler): @@ -15,7 +15,7 @@ class PreviewHandler(Handler): *** Everything here is subject to change. *** """ - def __call__(self, request, path, page_id): + def handler(self, request, path, page_id): if not request.user.is_staff: raise Http404 @@ -31,6 +31,11 @@ def __call__(self, request, path, page_id): # a 404 if the extra_path isn't consumed by any content type request.path = page.get_absolute_url() - response = self.build_response(request, page) + response = self.prepare() + if response: + return response + + response = self.render_to_response(self.get_context_data()) + response = self.finalize(response) response['Cache-Control'] = 'no-cache, must-revalidate, no-store, private' return response From fe916dffe41a7c717e9b91bf6bd55aa1a9053db3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 10:21:46 +0200 Subject: [PATCH 0020/1590] Class-based preview view actually works now --- feincms/contrib/preview/urls.py | 2 +- feincms/contrib/preview/views.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/contrib/preview/urls.py b/feincms/contrib/preview/urls.py index d4cb66b47..0df7ed6ae 100644 --- a/feincms/contrib/preview/urls.py +++ b/feincms/contrib/preview/urls.py @@ -3,5 +3,5 @@ from feincms.contrib.preview.views import PreviewHandler urlpatterns = patterns('', - url(r'^(.*)/_preview/(\d+)/$', PreviewHandler(), name='feincms_preview'), + url(r'^(.*)/_preview/(\d+)/$', PreviewHandler.as_view(), name='feincms_preview'), ) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 7727a9e6a..a720622db 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -19,17 +19,17 @@ def handler(self, request, path, page_id): if not request.user.is_staff: raise Http404 - page = get_object_or_404(Page, pk=page_id) + self.page = get_object_or_404(Page, pk=page_id) # Throw out request processor which will cause the page to-be-previewed # to be seen as inactive (which is the case, of course) - page.request_processors = [rp for rp in Page.request_processors if rp not in ( + self.page.request_processors = [rp for rp in Page.request_processors if rp not in ( processors.require_path_active_request_processor,)] # Remove _preview/42/ from URL, the rest of the handler code should not # know that anything about previewing. Handler.prepare will still raise # a 404 if the extra_path isn't consumed by any content type - request.path = page.get_absolute_url() + request.path = self.page.get_absolute_url() response = self.prepare() if response: From e0dae3362a3a1826ceaa620d417ebb323dfaf829 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 10:27:30 +0200 Subject: [PATCH 0021/1590] Add staticfiles context processor to example --- example/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/example/settings.py b/example/settings.py index 1c5f16399..b65201581 100644 --- a/example/settings.py +++ b/example/settings.py @@ -47,6 +47,7 @@ 'django.core.context_processors.i18n', 'django.core.context_processors.media', 'django.core.context_processors.request', + 'django.core.context_processors.static', ) TEMPLATE_LOADERS = ( From 741501534b7565b2062d6cdf4f4140f7f7ef45e2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 10:29:16 +0200 Subject: [PATCH 0022/1590] Remove our own mptt rebuilders in favor of those included with django-mptt itself --- docs/api/commands.rst | 4 - feincms/management/commands/rebuild_mptt.py | 32 +----- .../commands/rebuild_mptt_direct.py | 102 ------------------ 3 files changed, 1 insertion(+), 137 deletions(-) delete mode 100644 feincms/management/commands/rebuild_mptt_direct.py diff --git a/docs/api/commands.rst b/docs/api/commands.rst index 671daf7e4..62627d17c 100644 --- a/docs/api/commands.rst +++ b/docs/api/commands.rst @@ -28,10 +28,6 @@ management commands helped cleaning up the mess. :members: :noindex: -.. automodule:: feincms.management.commands.rebuild_mptt_direct - :members: - :noindex: - Miscellaneous commands ---------------------- diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index 7dc656cfd..373fe456d 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -10,42 +10,12 @@ """ from django.core.management.base import NoArgsCommand -from django.db import transaction from feincms.module.page.models import Page class Command(NoArgsCommand): help = "Run this manually to rebuild your mptt pointers. Only use in emergencies." - @staticmethod - def seq(start = 1): - """ - Returns an ever-increasing stream of numbers. The starting point can - be freely defined. - """ - while True: - yield start - start += 1 - - - @transaction.commit_manually def handle_noargs(self, **options): print "Rebuilding MPTT pointers for Page" - root = 1 - changes = set() - for page in Page.objects.filter(parent__isnull=True).order_by('tree_id'): - print " Processing subtree %d at %s" % ( page.tree_id, page.slug ) - - page.tree_id = root # Renumber tree_id for good measure - - self.renumber_mptt_tree(page, self.seq(1)) - - root += 1 - transaction.commit() - - def renumber_mptt_tree(self, obj, edge_count): - obj.lft = edge_count.next() - for c in obj.children.order_by('lft', 'rght').all(): - self.renumber_mptt_tree(c, edge_count) - obj.rght = edge_count.next() - obj.save() \ No newline at end of file + Page.tree.rebuild() diff --git a/feincms/management/commands/rebuild_mptt_direct.py b/feincms/management/commands/rebuild_mptt_direct.py deleted file mode 100644 index 98f40045b..000000000 --- a/feincms/management/commands/rebuild_mptt_direct.py +++ /dev/null @@ -1,102 +0,0 @@ -# encoding: utf-8 -""" -``rebuild_mptt_direct`` ------------------------ - -``rebuild_mptt_direct`` rebuilds your mptt pointers, bypassing the ORM. -Only use in emergencies. -""" - -import logging - -from django.core.management.base import NoArgsCommand -from django.db import transaction, connection, backend - -from feincms.module.page.models import Page - -class Command(NoArgsCommand): - help = "Manually rebuild MPTT hierarchy - should only be used to repair damaged databases" - - @transaction.commit_manually - def handle_noargs(self, **options): - logging.info("Rebuilding all MPTT trees") - try: - rebuild() - transaction.commit() - except backend.DatabaseError: - logging.exception("Unable to rebuild MPTT tree due to exception: rolling back all changes") - transaction.rollback() - -# TODO: Move this into utils and add a post-migrate/syncdb signal handler -# which can automatically rebuild after a fixture load? - -# Based heavily on the code from http://code.google.com/p/django-mptt/issues/detail?id=13 -qn = connection.ops.quote_name - -def rebuild(): - opts = Page._meta - tree = Page.tree - - cursor = connection.cursor() - cursor.execute('UPDATE %(table)s SET %(left)s = 0, %(right)s = 0, %(level)s = 0, %(tree_id)s = 0' % { - 'table': qn(opts.db_table), - 'left': qn(opts.get_field(tree.left_attr).column), - 'right': qn(opts.get_field(tree.right_attr).column), - 'level': qn(opts.get_field(tree.level_attr).column), - 'tree_id': qn(opts.get_field(tree.tree_id_attr).column) - }) - - cursor.execute('SELECT %(id_col)s FROM %(table)s WHERE %(parent_col)s is NULL %(orderby)s' % { - 'id_col': qn(opts.pk.column), - 'table': qn(opts.db_table), - 'parent_col': qn(opts.get_field(tree.parent_attr).column), - 'orderby': 'ORDER BY ' + ', '.join([qn(field) for field in opts.order_insertion_by]) if opts.order_insertion_by else '' - }) - - idx = 0 - for (pk, ) in cursor.fetchall(): - idx += 1 - _rebuild_helper(pk, 1, idx) - transaction.commit_unless_managed() - -def _rebuild_helper(pk, left, tree_id, level=0): - opts = Page._meta - tree = Page.tree - right = left + 1 - - cursor = connection.cursor() - cursor.execute('SELECT %(id_col)s FROM %(table)s WHERE %(parent_col)s = %(parent)d %(orderby)s' % { - 'id_col': qn(opts.pk.column), - 'table': qn(opts.db_table), - 'parent_col': qn(opts.get_field(tree.parent_attr).column), - 'parent': pk, - 'orderby': 'ORDER BY ' + ', '.join([qn(field) for field in opts.order_insertion_by]) if opts.order_insertion_by else '' - }) - - for (child_id, ) in cursor.fetchall(): - right = _rebuild_helper(child_id, right, tree_id, level+1) - - cursor.execute(""" - UPDATE %(table)s - SET - %(left_col)s = %(left)d, - %(right_col)s = %(right)d, - %(level_col)s = %(level)d, - %(tree_id_col)s = %(tree_id)d - WHERE - %(pk_col)s = %(pk)s - """ % { - 'table': qn(opts.db_table), - 'pk_col': qn(opts.pk.column), - 'left_col': qn(opts.get_field(tree.left_attr).column), - 'right_col': qn(opts.get_field(tree.right_attr).column), - 'level_col': qn(opts.get_field(tree.level_attr).column), - 'tree_id_col': qn(opts.get_field(tree.tree_id_attr).column), - 'pk': pk, - 'left': left, - 'right': right, - 'level': level, - 'tree_id': tree_id - }) - - return right + 1 From 62509a12726d8a67ad4fa03d0ffcecd6284c1a04 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 11:06:22 +0200 Subject: [PATCH 0023/1590] Fix docstring indentation problem --- feincms/default_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index f2d1fd0f1..c57fe8909 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -99,6 +99,6 @@ # ------------------------------------------------------------------------ #: Monkey-patch django.core.urlresvolers.reverse to be application-content aware? #: (The monkey patch is deprecated and should not be used anymore. Use the -#: ``app_reverse`` function and the ``{% app_reverse %}`` template tag instead.) +#: ``app_reverse`` function and the ``{% app_reverse %}`` template tag instead.) #: The value of this setting will be changed to False in FeinCMS 1.6. FEINCMS_REVERSE_MONKEY_PATCH = getattr(settings, 'FEINCMS_REVERSE_MONKEY_PATCH', True) From 26feb5b1de28ab0abc1352287d49da1d42d63c10 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 11:08:07 +0200 Subject: [PATCH 0024/1590] The AlreadyRegistered mptt exception isn't raised anymore, ever --- docs/faq.rst | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 9825d7e58..d804a4ab1 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -33,25 +33,6 @@ included PageManager... -I get a ``mptt.AlreadyRegistered`` exception when I try using the :mod:`~feincms.module.page` module! -===================================================================================================== - -This happens when the Django model loading code encounters an ``ImportError`` -when it loads the :mod:`~feincms.module.page` module for the first time. The -module is added to a list of postponed modules, and the import is retried -after all other applications have been successfully imported. This will -cause the ``mptt.register`` call to be executed twice though, which is why -you see this exception. We could catch this exception and go on as if -nothing had happened, but this hides a deeper problem somewhere which should -be fixed for good instead of papering over the issue. - -There are several ways how you might find out what's going wrong. Raise the -debugging level, try importing the page module (and other modules) from the -shell you get when you use ``./manage.py shell`` are some possibilities how -you might debug this problem. - - - I run ``syncdb`` and get a message about missing columns in the page table ========================================================================== From 34b4cedb1466545ca36aa0325a891d682a1e677b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 17:03:11 +0200 Subject: [PATCH 0025/1590] Make cropscale filter more flexible by allowing to specify a preferred cropping region --- feincms/templatetags/feincms_thumbnail.py | 35 +++++++++++++++-------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 8c1a59961..17f57dd8b 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -1,4 +1,5 @@ import os +import re from cStringIO import StringIO try: from PIL import Image @@ -18,12 +19,7 @@ register = template.Library() -def tryint(v): - try: - return int(v) - except ValueError: - return 999999 # Arbitrarily big number - +THUMBNAIL_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)$') @register.filter def thumbnail(filename, size='200x200'): @@ -47,7 +43,9 @@ def thumbnail(filename, size='200x200'): {{ object.image|thumbnail:"300x999999" }} """ - if not (filename and 'x' in size): + match = THUMBNAIL_SIZE_RE.match(size) + + if not (filename and match): # Better return empty than crash return u'' @@ -64,7 +62,8 @@ def thumbnail(filename, size='200x200'): filename = force_unicode(filename) # defining the size - x, y = [tryint(x) for x in size.split('x')] + w, h = int(matches['w']), int(matches['h']) + # defining the filename and the miniature filename try: basename, format = filename.rsplit('.', 1) @@ -99,6 +98,9 @@ def thumbnail(filename, size='200x200'): return storage.url(miniature) + +CROPSCALE_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)(-(?P\d+)x(?P\d+))?$') + @register.filter def cropscale(filename, size='200x200'): """ @@ -106,10 +108,14 @@ def cropscale(filename, size='200x200'): passed (as long as the initial image is bigger than the specification). """ - if not (filename and 'x' in size): + match = CROPSCALE_SIZE_RE.match(size) + + if not (filename and match): # Better return empty than crash return u'' + matches = match.groupdict() + # figure out storage if hasattr(filename, 'storage'): storage = filename.storage @@ -122,7 +128,12 @@ def cropscale(filename, size='200x200'): else: filename = force_unicode(filename) - w, h = [tryint(x) for x in size.split('x')] + w, h = int(matches['w']), int(matches['h']) + + if matches['x'] and matches['y']: + x, y = int(matches['x']), int(matches['y']) + else: + x, y = 50, 50 try: basename, format = filename.rsplit('.', 1) @@ -154,13 +165,13 @@ def cropscale(filename, size='200x200'): if dst_ratio < src_ratio: crop_height = src_height crop_width = crop_height * dst_ratio - x_offset = float(src_width - crop_width) / 2 + x_offset = float(src_width - crop_width) * x / 100 y_offset = 0 else: crop_width = src_width crop_height = crop_width / dst_ratio x_offset = 0 - y_offset = float(src_height - crop_height) / 2 + y_offset = float(src_height - crop_height) * y / 100 image = image.crop((x_offset, y_offset, x_offset+int(crop_width), y_offset+int(crop_height))) image = image.resize((dst_width, dst_height), Image.ANTIALIAS) From 3364531572b7e846bda8ca844c73b5d5df9f9cf1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2011 17:09:27 +0200 Subject: [PATCH 0026/1590] Add missing statement --- feincms/templatetags/feincms_thumbnail.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 17f57dd8b..0afb036a3 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -49,6 +49,8 @@ def thumbnail(filename, size='200x200'): # Better return empty than crash return u'' + matches = match.groupdict() + # figure out storage if hasattr(filename, 'storage'): storage = filename.storage From 3658d0f4c22455646491d84d5135e2c20507dcbb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 9 Aug 2011 13:34:14 +0200 Subject: [PATCH 0027/1590] Fix thumbnail filter typos --- feincms/templatetags/feincms_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 0afb036a3..158d396e6 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -89,7 +89,7 @@ def thumbnail(filename, size='200x200'): # Do not crash if file does not exist for some reason return storage.url(filename) - image.thumbnail([x, y], Image.ANTIALIAS) + image.thumbnail([w, h], Image.ANTIALIAS) buf = StringIO() if image.mode not in ('RGB', 'L'): image = image.convert('RGB') From 55eadbaa2fec4392bfb9d0b1ae4a37ef72d3cb38 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 10 Aug 2011 12:35:27 +0200 Subject: [PATCH 0028/1590] More helpful error in ItemEditor when no content types have been created yet --- feincms/admin/item_editor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 02f90a5de..3c9fc6cd6 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -67,6 +67,8 @@ def __init__(self, model, admin_site): def get_feincms_inlines(self, model): """ Generate genuine django inlines for registered content types. """ + model._needs_content_types() + inlines = [] for content_type in model._feincms_content_types: attrs = { From d13ab5592afc406a2ed1ae9ee3e9f7d9f0c1ec29 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 10 Aug 2011 12:36:21 +0200 Subject: [PATCH 0029/1590] Call ensure_completely_loaded in _needs_templates too --- feincms/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feincms/models.py b/feincms/models.py index 0a2d2bf46..8c5521c03 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -779,6 +779,8 @@ def content_type_for(cls, model): @classmethod def _needs_templates(cls): + ensure_completely_loaded() + # helper which can be used to ensure that either register_regions or # register_templates has been executed before proceeding if not hasattr(cls, 'template'): From eda2086baf5d6a650eb4eb73c0b35c5ce0199aff Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 10 Aug 2011 14:18:46 +0200 Subject: [PATCH 0030/1590] Add the application content configuration to _feincms_extra_context, too --- feincms/content/application/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index d73a1c458..6b98e43f4 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -367,6 +367,10 @@ def process(self, request, **kw): # context_processor request._feincms_extra_context.update(self.parameters) + # Save the application configuration for reuse elsewhere + request._feincms_extra_context.update({'app_config': dict(self.app_config, + urlconf_path=self.urlconf_path)}) + view_wrapper = self.app_config.get("view_wrapper", None) if view_wrapper: fn = partial( From 0ec2c9ebfc284784a12bd00fa192b9df0c97deb2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 11 Aug 2011 13:30:34 +0200 Subject: [PATCH 0031/1590] Import django-queryset-transform to feincms.utils This is much more useful than my prefilled attribute implementation, and so elegant and short that it does not warrant adding an external dependency. --- feincms/utils/queryset_transform.py | 112 ++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 feincms/utils/queryset_transform.py diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py new file mode 100644 index 000000000..2a66cbe6e --- /dev/null +++ b/feincms/utils/queryset_transform.py @@ -0,0 +1,112 @@ +# Straight import from https://github.com/simonw/django-queryset-transform + +""" +django_queryset_transform +========================= + +Allows you to register a transforming map function with a Django QuerySet +that will be executed only when the QuerySet itself has been evaluated. + +This allows you to build optimisations like "fetch all tags for these 10 rows" +while still benefiting from Django's lazy QuerySet evaluation. + +For example: + + def lookup_tags(item_qs): + item_pks = [item.pk for item in item_qs] + m2mfield = Item._meta.get_field_by_name('tags')[0] + tags_for_item = Tag.objects.filter( + item__in = item_pks + ).extra(select = { + 'item_id': '%s.%s' % ( + m2mfield.m2m_db_table(), m2mfield.m2m_column_name() + ) + }) + tag_dict = {} + for tag in tags_for_item: + tag_dict.setdefault(tag.item_id, []).append(tag) + for item in item_qs: + item.fetched_tags = tag_dict.get(item.pk, []) + + qs = Item.objects.filter(name__contains = 'e').transform(lookup_tags) + + for item in qs: + print item, item.fetched_tags + +Prints: + + Winter comes to Ogglesbrook [, , , ] + Summer now [, ] + +But only executes two SQL queries - one to fetch the items, and one to fetch ALL of the tags for those items. + +Since the transformer function can transform an evaluated QuerySet, it +doesn't need to make extra database calls at all - it should work for things +like looking up additional data from a cache.multi_get() as well. + +Originally inspired by http://github.com/lilspikey/django-batch-select/ + + + +LICENSE +======= + +Copyright (c) 2010, Simon Willison. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of Django nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +from django.db import models + +class TransformQuerySet(models.query.QuerySet): + def __init__(self, *args, **kwargs): + super(TransformQuerySet, self).__init__(*args, **kwargs) + self._transform_fns = [] + + def _clone(self, klass=None, setup=False, **kw): + c = super(TransformQuerySet, self)._clone(klass, setup, **kw) + c._transform_fns = self._transform_fns[:] + return c + + def transform(self, fn): + c = self._clone() + c._transform_fns.append(fn) + return c + + def iterator(self): + result_iter = super(TransformQuerySet, self).iterator() + if self._transform_fns: + results = list(result_iter) + for fn in self._transform_fns: + fn(results) + return iter(results) + return result_iter + +class TransformManager(models.Manager): + + def get_query_set(self): + return TransformQuerySet(self.model, using=self._db) From 78c6cd26d8442c2a18f3bf62c0e30da8435fc085 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 11 Aug 2011 14:51:50 +0200 Subject: [PATCH 0032/1590] Translations: Do not hit the database all the time when no translations exist --- feincms/translations.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/feincms/translations.py b/feincms/translations.py index 840c3fd04..75f10a87b 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -86,6 +86,13 @@ def only_language(self, language=short_language_code): return self.filter(translations__language_code=language) +class _NoTranslation(object): + """Simple marker for when no translations exist for a certain object + + Only used for caching.""" + pass + + class TranslatedObjectMixin(object): """ Mixin with helper methods. @@ -128,9 +135,15 @@ def get_translation(self, language_code=None): trans = cache.get(key) if trans is None: - trans = self._get_translation_object(self.translations.all(), language_code) + try: + trans = self._get_translation_object(self.translations.all(), language_code) + except ObjectDoesNotExist: + trans = _NoTranslation cache.set(key, trans) + if trans is _NoTranslation: + return None + # Assign self to prevent additional database queries trans.parent = self return trans @@ -180,7 +193,10 @@ def short_language_code(self): def save(self, *args, **kwargs): super(Inner, self).save(*args, **kwargs) + self.parent.purge_translation_cache() + def delete(self, *args, **kwargs): + super(Inner, self).delete(*args, **kwargs) self.parent.purge_translation_cache() return Inner From c23b3715d0037753af827498f1ba40e0e88a406a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sun, 14 Aug 2011 21:39:37 +0200 Subject: [PATCH 0033/1590] Revert "Remove the legacy filterspecs support" This reverts commit 060517ccec2ee8ddac5a0dc7c47d91820c746e8c. We aren't quite there yet... Django 1.3 will be supported for at least one more release. --- feincms/admin/filterspecs.py | 39 ++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index 0694eec0d..872960f3a 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -4,7 +4,15 @@ # Authors: Marinho Brandao # Guilherme M. Gondim (semente) -from django.contrib.admin.filters import FieldListFilter, ChoicesFieldListFilter +try: + from django.contrib.admin.filters import FieldListFilter, ChoicesFieldListFilter + legacy = False +except ImportError: # Django up to 1.3 + from django.contrib.admin.filterspecs import ( + FilterSpec as FieldListFilter, + ChoicesFilterSpec as ChoicesFieldListFilter) + legacy = True + from django.utils.encoding import smart_unicode from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ @@ -21,7 +29,12 @@ class ParentFieldListFilter(ChoicesFieldListFilter): def __init__(self, f, request, params, model, model_admin, field_path=None): from feincms.utils import shorten_string - super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin, field_path) + + try: + super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin, field_path) + except TypeError: # Django 1.2 + super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin) + parent_ids = model.objects.exclude(parent=None).values_list("parent__id", flat=True).order_by("parent__id").distinct() parents = model.objects.filter(pk__in=parent_ids).values_list("pk", "title", "level") self.lookup_choices = [(pk, "%s%s" % (" " * level, shorten_string(title, max_length=25))) for pk, title, level in parents] @@ -82,9 +95,19 @@ def title(self): return _('Category') -FieldListFilter.register(lambda f: getattr(f, 'parent_filter', False), - ParentFieldListFilter, - take_priority=True) -FieldListFilter.register(lambda f: getattr(f, 'category_filter', False), - CategoryFieldListFilter, - take_priority=True) +if legacy: + # registering the filter + FieldListFilter.filter_specs.insert(0, + (lambda f: getattr(f, 'parent_filter', False), ParentFieldListFilter) + ) + + FieldListFilter.filter_specs.insert(1, + (lambda f: getattr(f, 'category_filter', False), CategoryFieldListFilter) + ) +else: + FieldListFilter.register(lambda f: getattr(f, 'parent_filter', False), + ParentFieldListFilter, + take_priority=True) + FieldListFilter.register(lambda f: getattr(f, 'category_filter', False), + CategoryFieldListFilter, + take_priority=True) From 5192a7b5e3cdee177f94bd5fdbe30d583b0244b8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 15 Aug 2011 09:37:59 +0200 Subject: [PATCH 0034/1590] We require Django >=1.3.0 now --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 9c92055a6..4b2793a4a 100755 --- a/setup.py +++ b/setup.py @@ -14,13 +14,13 @@ except pkg_resources.DistributionNotFound: try: import django - if django.VERSION[0] >= 1 and django.VERSION[1] >= 2 and django.VERSION[2] >= 0: + if django.VERSION[0] >= 1 and django.VERSION[1] >= 3 and django.VERSION[2] >= 0: add_django_dependency = False except ImportError: pass Distribution({ - "setup_requires": add_django_dependency and ['Django >=1.2.0'] or [] + "setup_requires": add_django_dependency and ['Django >=1.3.0'] or [] }) import feincms @@ -47,7 +47,7 @@ 'Topic :: Software Development :: Libraries :: Application Frameworks', ], install_requires=[ - #'Django >=1.2.0' # See http://github.com/feincms/feincms/issues/closed#issue/50 + #'Django >=1.3.0' # See http://github.com/feincms/feincms/issues/closed#issue/50 ], requires=[ #'lxml', # only needed for rich text cleansing From 64e1db7d2f785f0c5bb712d35ef645c0903963f9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 15 Aug 2011 14:37:19 +0200 Subject: [PATCH 0035/1590] Emit a DeprecationWarning if the reverse() monkey patch is still used --- feincms/content/application/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 6b98e43f4..816542de2 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -225,6 +225,12 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, return _reverse(viewname, urlconf, args, kwargs, prefix, *vargs, **vkwargs) if settings.FEINCMS_REVERSE_MONKEY_PATCH: + import warnings + warnings.warn("FeinCMS will stop monkey-patching Django's 'django.core.urlresolvers.reverse'" + " method in v1.6. You should use the explicit 'feincms.content.application.models.app_reverse'" + " function and {% app_reverse %} template tag instead. Set 'FEINCMS_REVERSE_MONKEY_PATCH' + " to False to use the new behavior now.", + DeprecationWarning) urlresolvers.reverse = reverse From e41d7def684b6f9a316207c0404880ed6d7d42b3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 15 Aug 2011 14:40:57 +0200 Subject: [PATCH 0036/1590] Fix typo --- feincms/content/application/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 816542de2..542eea807 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -228,7 +228,7 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, import warnings warnings.warn("FeinCMS will stop monkey-patching Django's 'django.core.urlresolvers.reverse'" " method in v1.6. You should use the explicit 'feincms.content.application.models.app_reverse'" - " function and {% app_reverse %} template tag instead. Set 'FEINCMS_REVERSE_MONKEY_PATCH' + " function and {% app_reverse %} template tag instead. Set 'FEINCMS_REVERSE_MONKEY_PATCH'" " to False to use the new behavior now.", DeprecationWarning) urlresolvers.reverse = reverse From 4faf5b8f926019bc99c931703c8d78e86e4d4484 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 15 Aug 2011 17:11:10 +0200 Subject: [PATCH 0037/1590] Add missing package to setup.py Thanks to jonasvp for noticing. --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 9c92055a6..89a31e076 100755 --- a/setup.py +++ b/setup.py @@ -88,6 +88,7 @@ 'feincms.views', 'feincms.views.cbv', 'feincms.views.generic', + 'feincms.views.legacy', ], include_package_data=True, zip_safe=False, From bb293293a6ecdb2a41b6ee872fdd4b148e00fcec Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 15 Aug 2011 17:22:00 +0200 Subject: [PATCH 0038/1590] Refactor thumbnail filters a bit --- feincms/templatetags/feincms_thumbnail.py | 215 +++++++++++----------- 1 file changed, 103 insertions(+), 112 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 158d396e6..958b85f10 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -19,75 +19,71 @@ register = template.Library() -THUMBNAIL_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)$') +class Thumbnailer(object): + THUMBNAIL_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)$') + MARKER = '_thumb_' -@register.filter -def thumbnail(filename, size='200x200'): - """ - Creates a thumbnail from the image passed, returning its path:: - - {{ object.image|thumbnail:"400x300" }} - OR - {{ object.image.name|thumbnail:"400x300" }} - - You can pass either an ``ImageField``, ``FileField`` or the ``name`` - but not the ``url`` attribute of an ``ImageField`` or ``FileField``. - - The dimensions passed are treated as a bounding box. The aspect ratio of - the initial image is preserved. Images aren't blown up in size if they - are already smaller. - - Both width and height must be specified. If you do not care about one - of them, just set it to an arbitrarily large number:: - - {{ object.image|thumbnail:"300x999999" }} - """ - - match = THUMBNAIL_SIZE_RE.match(size) - - if not (filename and match): - # Better return empty than crash - return u'' + def __init__(self, filename, size='200x200'): + self.filename = filename + self.size = size - matches = match.groupdict() + @property + def url(self): + return unicode(self) - # figure out storage - if hasattr(filename, 'storage'): - storage = filename.storage - else: - storage = default_storage + def __unicode__(self): + match = self.THUMBNAIL_SIZE_RE.match(self.size) + if not (self.filename and match): + return u'' - # figure out name - if hasattr(filename, 'name'): - filename = filename.name - else: - filename = force_unicode(filename) + matches = match.groupdict() - # defining the size - w, h = int(matches['w']), int(matches['h']) + # figure out storage + if hasattr(self.filename, 'storage'): + storage = self.filename.storage + else: + storage = default_storage - # defining the filename and the miniature filename - try: - basename, format = filename.rsplit('.', 1) - except ValueError: - basename, format = filename, 'jpg' - miniature = basename + '_thumb_' + size + '.' + format + # figure out name + if hasattr(self.filename, 'name'): + filename = self.filename.name + else: + filename = force_unicode(self.filename) - if not storage.exists(miniature): - generate = True - else: + # defining the filename and the miniature filename try: - generate = storage.modified_time(miniature)\d+)x(?P\d+)(-(?P\d+)x(?P\d+))?$') - -@register.filter -def cropscale(filename, size='200x200'): - """ - Scales the image down and crops it so that its size equals exactly the size - passed (as long as the initial image is bigger than the specification). - """ - - match = CROPSCALE_SIZE_RE.match(size) - - if not (filename and match): - # Better return empty than crash - return u'' - - matches = match.groupdict() - - # figure out storage - if hasattr(filename, 'storage'): - storage = filename.storage - else: - storage = default_storage + return storage.url(miniature) - # figure out name - if hasattr(filename, 'name'): - filename = filename.name - else: - filename = force_unicode(filename) - w, h = int(matches['w']), int(matches['h']) +class CropscaleThumbnailer(Thumbnailer): + THUMBNAIL_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)(-(?P\d+)x(?P\d+))?$') + MARKER = '_cropscale_' - if matches['x'] and matches['y']: - x, y = int(matches['x']), int(matches['y']) - else: - x, y = 50, 50 - - try: - basename, format = filename.rsplit('.', 1) - except ValueError: - basename, format = filename, 'jpg' - miniature = basename + '_cropscale_' + size + '.' + format - - if not storage.exists(miniature): - generate = True - else: + def generate(self, storage, original, size, miniature): try: - generate = storage.modified_time(miniature) Date: Tue, 16 Aug 2011 10:57:12 +0200 Subject: [PATCH 0039/1590] FeinCMS v1.4.1 The I-failed-to-make-a-proper-release release. --- feincms/__init__.py | 2 +- setup.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index c53879862..60743a479 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 4, 0) +VERSION = (1, 4, 1) __version__ = '.'.join(map(str, VERSION)) diff --git a/setup.py b/setup.py index 89a31e076..9c92055a6 100755 --- a/setup.py +++ b/setup.py @@ -88,7 +88,6 @@ 'feincms.views', 'feincms.views.cbv', 'feincms.views.generic', - 'feincms.views.legacy', ], include_package_data=True, zip_safe=False, From 98c597b8265735e723fe3b44f18331c032b9cb23 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Aug 2011 11:23:10 +0200 Subject: [PATCH 0040/1590] Open 1.5 branch --- feincms/__init__.py | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 60743a479..ad0800763 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 4, 1) +VERSION = (1, 5, 0, 'pre') __version__ = '.'.join(map(str, VERSION)) diff --git a/setup.py b/setup.py index 4b2793a4a..925b2f432 100755 --- a/setup.py +++ b/setup.py @@ -88,6 +88,7 @@ 'feincms.views', 'feincms.views.cbv', 'feincms.views.generic', + 'feincms.views.legacy', ], include_package_data=True, zip_safe=False, From 83173d1a358b0e0eed9ecbc04970c018d38852a1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Aug 2011 22:31:26 +0200 Subject: [PATCH 0041/1590] Allow passing in callables as extensions --- feincms/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index 8c5521c03..f0659a829 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -329,7 +329,11 @@ def register_extensions(cls, *extensions): raise ImproperlyConfigured, '%s is not a valid extension for %s' % ( ext, cls.__name__) - # Not a string, so take our chances and just try to access "register" + # Not a string, maybe a callable? + elif hasattr(ext, '__call__'): + fn = ext + + # Take our chances and just try to access "register" else: fn = ext.register From 19f2cb15a6b9f674d188d98f4059abeb62b784a4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Aug 2011 23:06:25 +0200 Subject: [PATCH 0042/1590] Remove feincms.templatetags.utils -- it has been deprecated for a long time already --- feincms/templatetags/utils.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 feincms/templatetags/utils.py diff --git a/feincms/templatetags/utils.py b/feincms/templatetags/utils.py deleted file mode 100644 index 5391fbb9e..000000000 --- a/feincms/templatetags/utils.py +++ /dev/null @@ -1,7 +0,0 @@ -import warnings -warnings.warn( - 'Please use feincms.utils.templatetags instead of feincms.templatetags.utils', - DeprecationWarning - ) - -from feincms.utils.templatetags import * From 36e7c6db5554a12d1286c36279c37bee9bb4d274 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Aug 2011 23:11:58 +0200 Subject: [PATCH 0043/1590] Remove csrf_token stub for Django < 1.2 --- feincms/templatetags/feincms_compat_tags.py | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 feincms/templatetags/feincms_compat_tags.py diff --git a/feincms/templatetags/feincms_compat_tags.py b/feincms/templatetags/feincms_compat_tags.py deleted file mode 100644 index e2a7707f6..000000000 --- a/feincms/templatetags/feincms_compat_tags.py +++ /dev/null @@ -1,20 +0,0 @@ -from django import template - - -register = template.Library() - - -def csrf_token(): - """ - Dummy implementation for older versions of Django - """ - - # Should be deprecated, Django versions prior to 1.2 aren't supported - # anymore. - return u'' - - -try: - from django.template.defaulttags import csrf_token -except ImportError: - register.simple_tag(csrf_token) From b6acf0eeb8862d683f3927bac40667eb1ebde9b4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Aug 2011 23:32:23 +0200 Subject: [PATCH 0044/1590] Remove `user_can` support -- Django supports object-level permissions now --- feincms/admin/tree_editor.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 7b2766a2d..af6098e5a 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -276,15 +276,7 @@ def _toggle_boolean(self, request): except self.model.DoesNotExist: return HttpResponseNotFound("Object does not exist") - can_change = False - - if hasattr(obj, "user_can") and obj.user_can(request.user, change_page=True): - # Was added in c7f04dfb5d, but I've no idea what user_can is about. - can_change = True - else: - can_change = self.has_change_permission(request, obj=obj) - - if not can_change: + if not self.has_change_permission(request, obj=obj): logging.warning("Denied AJAX request by %s to toggle boolean %s for object %s", request.user, attr, item_id) return HttpResponseForbidden("You do not have permission to access this object") From 0f7ead336c02859149703152e3f4b1221a3140b6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Aug 2011 23:36:45 +0200 Subject: [PATCH 0045/1590] Remove redundant call to _needs_content_types in the item editor --- feincms/admin/item_editor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 3c9fc6cd6..e9eb07fc7 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -203,8 +203,6 @@ def add_view(self, request, form_url='', extra_context=None): return super(ItemEditor, self).add_view(request, form_url, context) def change_view(self, request, object_id, extra_context=None): - self.model._needs_content_types() - # Recognize frontend editing requests # This is done here so that the developer does not need to add # additional entries to # urls.py or something... From 78b9e3e5602603e00b54295aef642e2f58dbb414 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 07:13:16 +0200 Subject: [PATCH 0046/1590] Deprecate feincms.admin.editor module --- docs/admin.rst | 16 ++++++++-------- example/admin.py | 4 ++-- example/settings.py | 1 - feincms/admin/editor.py | 6 ++++++ feincms/content/application/models.py | 2 +- feincms/content/comments/models.py | 2 +- feincms/content/medialibrary/models.py | 2 +- feincms/content/richtext/models.py | 2 +- feincms/content/section/models.py | 2 +- feincms/module/blog/models.py | 4 ++-- feincms/module/page/models.py | 13 ++++++------- 11 files changed, 29 insertions(+), 25 deletions(-) diff --git a/docs/admin.rst b/docs/admin.rst index 2785d7bd5..78a91bc06 100644 --- a/docs/admin.rst +++ b/docs/admin.rst @@ -35,10 +35,10 @@ Usage is as follows:: And inside your ``admin.py`` file:: from django.contrib import admin - from feincms.admin import editor + from feincms.admin import tree_editor from yourapp.models import YourModel - class YourModelAdmin(editor.TreeEditor): + class YourModelAdmin(tree_editor.TreeEditor): pass admin.site.register(YourModel, YourModelAdmin) @@ -68,7 +68,7 @@ the page editor however. Usage:: from django.contrib import admin - from feincms.admin import editor + from feincms.admin import tree_editor import mptt class Category(models.Model): @@ -79,9 +79,9 @@ Usage:: # ... mptt.register(Category) - class CategoryAdmin(editor.TreeEditor): + class CategoryAdmin(tree_editor.TreeEditor): list_display = ('__unicode__', 'active_toggle') - active_toggle = editor.ajax_editable_boolean('active', _('active')) + active_toggle = tree_editor.ajax_editable_boolean('active', _('active')) @@ -222,15 +222,15 @@ more than the following code: ``admin.py``:: from django.contrib import admin - from feincms.admin import editor + from feincms.admin import item_editor, tree_editor from myapp.models import Page - class PageAdmin(editor.ItemEditor, editor.TreeEditor): + class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): fieldsets = [ (None, { 'fields': ['active', 'title', 'slug'], }), - editor.FEINCMS_CONTENT_FIELDSET, + item_editor.FEINCMS_CONTENT_FIELDSET, ] list_display = ['active', 'title'] prepopulated_fields = {'slug': ('title',)} diff --git a/example/admin.py b/example/admin.py index 89fa569d7..9df2fc47b 100644 --- a/example/admin.py +++ b/example/admin.py @@ -1,11 +1,11 @@ from django.contrib import admin -from feincms.admin import editor +from feincms.admin import tree_editor from example.models import Category -class CategoryAdmin(editor.TreeEditor): +class CategoryAdmin(tree_editor.TreeEditor): list_display = ('name', 'slug') list_filter = ('parent',) prepopulated_fields = { diff --git a/example/settings.py b/example/settings.py index b65201581..bf754681c 100644 --- a/example/settings.py +++ b/example/settings.py @@ -93,7 +93,6 @@ 'feincms', 'feincms._internal', 'feincms.admin', - 'feincms.admin.editor', 'feincms.admin.filterspecs', 'feincms.admin.item_editor', 'feincms.admin.tree_editor', diff --git a/feincms/admin/editor.py b/feincms/admin/editor.py index 9c9d30f8b..65afabe3c 100644 --- a/feincms/admin/editor.py +++ b/feincms/admin/editor.py @@ -1,3 +1,9 @@ +import warnings +warnings.warn("Accessing the item and tree editor through `feincms.admin.editor`" + " has been deprecated. Please use `feincms.admin.item_editor` and" + " `feincms.admin.tree_editor` instead.", + DeprecationWarning) + from feincms.admin.item_editor import ItemEditor, ItemEditorForm from feincms.admin.tree_editor import TreeEditor, ajax_editable_boolean, \ ajax_editable_boolean_cell, django_boolean_icon diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 542eea807..199fede9d 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -14,7 +14,7 @@ from django.utils.translation import ugettext_lazy as _ from feincms import settings -from feincms.admin.editor import ItemEditorForm +from feincms.admin.item_editor import ItemEditorForm from feincms.contrib.fields import JSONField from feincms.utils import get_object diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index e5fd7c653..f755ec910 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -34,7 +34,7 @@ class Meta: @classmethod def initialize_type(cls): - from feincms.admin.editor import ItemEditorForm + from feincms.admin.item_editor import ItemEditorForm class CommentContentAdminForm(ItemEditorForm): def __init__(self, *args, **kwargs): super(CommentContentAdminForm, self).__init__(*args, **kwargs) diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 4105d7fb3..2fb3c2dcd 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -14,7 +14,7 @@ from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from feincms.admin.editor import ItemEditorForm +from feincms.admin.item_editor import ItemEditorForm from feincms.module.medialibrary.models import MediaFile from feincms.templatetags import feincms_thumbnail diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index bf528ab17..262a627b5 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -8,7 +8,7 @@ from django.utils.translation import ugettext_lazy as _ from feincms import settings -from feincms.admin.editor import ItemEditorForm +from feincms.admin.item_editor import ItemEditorForm from feincms.utils import get_object class RichTextContentAdminForm(ItemEditorForm): diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 52d96067c..84c81f1b0 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -8,7 +8,7 @@ from django.utils.translation import ugettext_lazy as _ from feincms import settings -from feincms.admin.editor import ItemEditorForm +from feincms.admin.item_editor import ItemEditorForm from feincms.module.medialibrary.models import MediaFile from feincms.content.medialibrary.models import MediaFileWidget diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index 1627d9c8d..246d6a332 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -12,7 +12,7 @@ from django.db.models import signals from django.utils.translation import ugettext_lazy as _ -from feincms.admin import editor +from feincms.admin import item_editor from feincms.management.checker import check_database_schema from feincms.models import Base from feincms.utils import get_object @@ -64,7 +64,7 @@ def register_extension(cls, register_fn): signals.post_syncdb.connect(check_database_schema(Entry, __name__), weak=False) -class EntryAdmin(editor.ItemEditor): +class EntryAdmin(item_editor.ItemEditor): date_hierarchy = 'published_on' list_display = ('__unicode__', 'published', 'published_on') list_filter = ('published',) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index d4a657c2a..2c851dfaa 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -31,8 +31,7 @@ from mptt.models import MPTTModel from feincms import settings, ensure_completely_loaded -from feincms.admin import editor -from feincms.admin import item_editor +from feincms.admin import item_editor, tree_editor from feincms.management.checker import check_database_schema from feincms.models import Base, create_base_model from feincms.module.page import processors @@ -674,7 +673,7 @@ def clean(self): return cleaned_data # ------------------------------------------------------------------------ -class PageAdmin(editor.ItemEditor, editor.TreeEditor): +class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): class Media: css = {} js = [] @@ -730,7 +729,7 @@ def __init__(self, *args, **kwargs): if not f.editable: self.readonly_fields.append(f.name) - in_navigation_toggle = editor.ajax_editable_boolean('in_navigation', _('in navigation')) + in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) def _actions_column(self, page): editable = getattr(page, 'feincms_editable', True) @@ -794,13 +793,13 @@ def is_visible_admin(self, page): # parent page's invisibility is inherited if page.id in self._visible_pages: self._visible_pages.remove(page.id) - return editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('inherited')) + return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('inherited')) if page.active and not page.id in self._visible_pages: # is active but should not be shown, so visibility limited by extension: show a "not active" - return editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('extensions')) + return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('extensions')) - return editor.ajax_editable_boolean_cell(page, 'active') + return tree_editor.ajax_editable_boolean_cell(page, 'active') is_visible_admin.allow_tags = True is_visible_admin.short_description = _('is active') is_visible_admin.editable_boolean_field = 'active' From ce5830285663671cd6daea68fc85b506b7daa4ad Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 07:21:25 +0200 Subject: [PATCH 0047/1590] Add full list of modules for coverage report --- example/settings.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/example/settings.py b/example/settings.py index bf754681c..95898013e 100644 --- a/example/settings.py +++ b/example/settings.py @@ -184,9 +184,12 @@ 'feincms.utils.templatetags', 'feincms.views', 'feincms.views.base', - #'feincms.views.cbv', # Makes test-suite only runnable with Django 1.3 - #'feincms.views.cbv.urls', - #'feincms.views.cbv.views', + 'feincms.views.cbv', + 'feincms.views.cbv.urls', + 'feincms.views.cbv.views', + 'feincms.views.legacy', + 'feincms.views.legacy.urls', + 'feincms.views.legacy.views', 'feincms.views.decorators', 'feincms.views.generic', 'feincms.views.generic.create_update', From c7159f7ffcd15811e30426434cdd15bde82c998b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 07:24:31 +0200 Subject: [PATCH 0048/1590] Remove two unused imports --- feincms/module/page/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 2c851dfaa..28b784a1b 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -35,7 +35,6 @@ from feincms.management.checker import check_database_schema from feincms.models import Base, create_base_model from feincms.module.page import processors -from feincms.utils import get_object, copy_model_instance import feincms.admin.filterspecs # ------------------------------------------------------------------------ From 1fba4b0e7aae7f54d1abbed5246da2e53e164e75 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 07:25:28 +0200 Subject: [PATCH 0049/1590] Deprecate prefilled attributes feincms.utils.queryset_transform and/or batchselect should be used instead. --- feincms/utils/__init__.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index f1faf312a..8294a1d7d 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -50,6 +50,8 @@ class Entry(Base): {% feincms_prefill_entry_list object_list "authors,richtextcontent_set,imagecontent_set" %} """ +import warnings + from django.db import connection from django.db.models import AutoField from django.db.models.fields import related @@ -76,6 +78,13 @@ def get_object(path, fail_silently=False): # ------------------------------------------------------------------------ def prefilled_attribute(name): + warnings.warn("FeinCMS' own prefilled attributes mechanism for reducing" + " the database query count has been deprecated in favor of other," + " more widely used solutions such as django-queryset-transform" + " (bundled as `feincms.utils.queryset_transform`) and" + " django-batchselect.", + DeprecationWarning) + key = '_prefill_%s' % name def _prop(self): @@ -108,6 +117,13 @@ def prefill_entry_list(queryset, *attrs, **kwargs): content objects. """ + warnings.warn("FeinCMS' own prefilled attributes mechanism for reducing" + " the database query count has been deprecated in favor of other," + " more widely used solutions such as django-queryset-transform" + " (bundled as `feincms.utils.queryset_transform`) and" + " django-batchselect.", + DeprecationWarning) + region = kwargs.get('region', None) # Evaluate queryset. We need a list of objects, because we need to iterate over From 493e2ea62c9ee24b8440cc029d7a9c7d94d6e9f9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Aug 2011 11:38:33 +0200 Subject: [PATCH 0050/1590] Look, it is 2011! --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 4268a6f6f..dd349ffa3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2010, FEINHEIT GmbH and individual contributors. +Copyright (c) 2009-2011, FEINHEIT GmbH and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, From 49829fc885d8bf0c559fef6c0f9f9cdf7566649f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 08:02:10 +0200 Subject: [PATCH 0051/1590] Fix is_equal_or_parent_of example --- feincms/module/page/templatetags/feincms_page_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 825295394..f375a3a25 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -312,7 +312,7 @@ def is_equal_or_parent_of(page1, page2): example adds a CSS class ``current`` to the current main navigation entry:: {% for page in navigation %} - + {{ page.title }} {% endfor %} """ From 6adb2d58d1ee00d206d0240c7db26c10ed7c77d8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 07:33:39 +0200 Subject: [PATCH 0052/1590] Convert active_filters to a dict --- .../module/page/extensions/datepublisher.py | 4 ++-- feincms/module/page/extensions/sites.py | 9 ++++----- feincms/module/page/models.py | 19 ++++++++++++------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/feincms/module/page/extensions/datepublisher.py b/feincms/module/page/extensions/datepublisher.py index f4a5ca0f3..9476cf78f 100644 --- a/feincms/module/page/extensions/datepublisher.py +++ b/feincms/module/page/extensions/datepublisher.py @@ -66,8 +66,8 @@ def granular_save(obj, *args, **kwargs): if hasattr(cls.objects, 'add_to_active_filters'): cls.objects.add_to_active_filters( Q(publication_date__lte=granular_now) & - (Q(publication_end_date__isnull=True) | Q(publication_end_date__gt=granular_now)) - ) + (Q(publication_end_date__isnull=True) | Q(publication_end_date__gt=granular_now)), + key='datepublisher') def datepublisher_admin(self, page): return u'%s – %s' % ( diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index 76a7cacbb..706445475 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -11,12 +11,11 @@ def current_site(queryset): def register(cls, admin_cls): - cls.add_to_class('site', - models.ForeignKey(Site, - verbose_name=_('Site'), + cls.add_to_class('site', + models.ForeignKey(Site, + verbose_name=_('Site'), default=settings.SITE_ID, )) - PageManager.add_to_active_filters(current_site) + PageManager.add_to_active_filters(current_site, key='current_site') admin_cls.list_display.extend(['site']) - diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 28b784a1b..c84ff0405 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -48,17 +48,17 @@ class ActiveAwareContentManagerMixin(object): should either adopt this mixin or implement a similar interface. """ - # A list of filters which are used to determine whether a page is active or not. + # A dict of filters which are used to determine whether a page is active or not. # Extended for example in the datepublisher extension (date-based publishing and # un-publishing of pages) - active_filters = () + active_filters = {} @classmethod def apply_active_filters(cls, queryset): """ Apply all filters defined to the queryset passed and return the result. """ - for filt in cls.active_filters: + for filt in cls.active_filters.values(): if callable(filt): queryset = filt(queryset) else: @@ -67,15 +67,20 @@ def apply_active_filters(cls, queryset): return queryset @classmethod - def add_to_active_filters(cls, filter): + def add_to_active_filters(cls, filter, key=None): """ Add a new clause to the active filters. A filter may be either a Q object to be applied to the content class or a callable taking a queryset and spitting out a new one. + + If a filter with the given `key` already exists, the new filter + replaces the old. """ if not cls.active_filters: - cls.active_filters = list() - cls.active_filters.append(filter) + cls.active_filters = {} + if key is None: + key = filter + cls.active_filters[key] = filter def active(self): """ @@ -235,7 +240,7 @@ def from_request(self, request, best_match=False): return self.best_match_for_request(request, raise404=False) return self.for_request(request) -PageManager.add_to_active_filters( Q(active=True) ) +PageManager.add_to_active_filters(Q(active=True)) # MARK: - # ------------------------------------------------------------------------ From 2149f9f65060fea5c91852597e064799e5726898 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 07:46:19 +0200 Subject: [PATCH 0053/1590] Make request and response processors more easily replacable --- feincms/contrib/preview/views.py | 6 ++- .../module/page/extensions/translations.py | 6 ++- feincms/module/page/models.py | 49 +++++++++++++++---- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index a720622db..2b252046a 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -23,8 +23,10 @@ def handler(self, request, path, page_id): # Throw out request processor which will cause the page to-be-previewed # to be seen as inactive (which is the case, of course) - self.page.request_processors = [rp for rp in Page.request_processors if rp not in ( - processors.require_path_active_request_processor,)] + self.page.request_processors = self.page.request_processors.copy() + self.page.register_request_processor( + lambda page, response: None, # Do nothing + key='path_active') # Remove _preview/42/ from URL, the rest of the handler code should not # know that anything about previewing. Handler.prepare will still raise diff --git a/feincms/module/page/extensions/translations.py b/feincms/module/page/extensions/translations.py index 21885ea0a..9da81c8ec 100644 --- a/feincms/module/page/extensions/translations.py +++ b/feincms/module/page/extensions/translations.py @@ -109,9 +109,11 @@ def register(cls, admin_cls): )) if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": - cls.register_request_processors(translations_request_processor_explicit) + cls.register_request_processors(translations_request_processor_explicit, + key='translations') else: # STANDARD - cls.register_request_processors(translations_request_processor_standard) + cls.register_request_processors(translations_request_processor_standard, + key='translations') @monkeypatch_method(cls) def get_redirect_to_target(self, request): diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c84ff0405..488d025a4 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -24,6 +24,7 @@ from django.forms.models import model_to_dict from django.forms.util import ErrorList from django.http import Http404, HttpResponseRedirect +from django.utils.datastructures import SortedDict from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _, ugettext from django.db.transaction import commit_on_success @@ -283,8 +284,8 @@ class Page(create_base_model(MPTTModel)): _cached_url = models.CharField(_('Cached URL'), max_length=300, blank=True, editable=False, default='', db_index=True) - request_processors = [] - response_processors = [] + request_processors = SortedDict() + response_processors = SortedDict() cache_key_components = [ lambda p: django_settings.SITE_ID, lambda p: p._django_content_type.id, lambda p: p.id ] @@ -489,7 +490,7 @@ def setup_request(self, request): request.path), }) - for fn in self.request_processors: + for fn in reversed(self.request_processors.values()): r = fn(self, request) if r: return r @@ -499,7 +500,7 @@ def finalize_response(self, request, response): called to modify the response, eg. for setting cache or expiration headers, keeping statistics, etc. """ - for fn in self.response_processors: + for fn in self.response_processors.values(): fn(self, request, response) def get_redirect_to_target(self, request): @@ -508,6 +509,22 @@ def get_redirect_to_target(self, request): """ return self.redirect_to + @classmethod + def register_request_processor(cls, fn, key=None): + """ + Registers the passed callable as request processor. A request processor + always receives two arguments, the current page object and the request. + """ + cls.request_processors[fn if key is None else key] = fn + + @classmethod + def register_response_processor(cls, fn, key=None): + """ + Registers the passed callable as response processor. A response processor + always receives three arguments, the current page object, the request + and the response. + """ + cls.response_processors[fn if key is None else key] = fn @classmethod def register_request_processors(cls, *processors): @@ -516,7 +533,12 @@ def register_request_processors(cls, *processors): always receives two arguments, the current page object and the request. """ - cls.request_processors[0:0] = processors + warnings.warn("register_request_processors has been deprecated," + " use register_request_processor instead.", + DeprecationWarning) + + for processor in processors: + cls.register_request_processor(processor) @classmethod def register_response_processors(cls, *processors): @@ -526,7 +548,12 @@ def register_response_processors(cls, *processors): and the response. """ - cls.response_processors.extend(processors) + warnings.warn("register_response_processors has been deprecated," + " use register_response_processor instead.", + DeprecationWarning) + + for processor in processors: + cls.register_response_processor(processor) @classmethod def register_extension(cls, register_fn): @@ -548,12 +575,14 @@ def register_extension(cls, register_fn): # ------------------------------------------------------------------------ # Our default request processors -Page.register_request_processors(processors.require_path_active_request_processor, - processors.redirect_request_processor) +Page.register_request_processor(processors.require_path_active_request_processor, + key='path_active') +Page.register_request_processor(processors.redirect_request_processor, + key='redirect') if settings.FEINCMS_FRONTEND_EDITING: - Page.register_request_processors( - processors.frontendediting_request_processor) + Page.register_request_processor(processors.frontendediting_request_processor, + key='frontend_editing') signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) From 888b26882fb9908bd2b5edbbe24a09d9cb864354 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 07:51:00 +0200 Subject: [PATCH 0054/1590] Move ActiveAwareContentManagerMixin to a more officially-sounding place --- feincms/module/page/models.py | 51 +---------------------------------- feincms/utils/managers.py | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 50 deletions(-) create mode 100644 feincms/utils/managers.py diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 488d025a4..2b1386c80 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -36,58 +36,9 @@ from feincms.management.checker import check_database_schema from feincms.models import Base, create_base_model from feincms.module.page import processors +from feincms.utils.managers import ActiveAwareContentManagerMixin import feincms.admin.filterspecs -# ------------------------------------------------------------------------ -class ActiveAwareContentManagerMixin(object): - """ - Implement what's necessary to add some kind of "active" state for content - objects. The notion of active is defined by a number of filter rules that - must all match (AND) for the object to be active. - - A Manager for a content class using the "datepublisher" extension - should either adopt this mixin or implement a similar interface. - """ - - # A dict of filters which are used to determine whether a page is active or not. - # Extended for example in the datepublisher extension (date-based publishing and - # un-publishing of pages) - active_filters = {} - - @classmethod - def apply_active_filters(cls, queryset): - """ - Apply all filters defined to the queryset passed and return the result. - """ - for filt in cls.active_filters.values(): - if callable(filt): - queryset = filt(queryset) - else: - queryset = queryset.filter(filt) - - return queryset - - @classmethod - def add_to_active_filters(cls, filter, key=None): - """ - Add a new clause to the active filters. A filter may be either - a Q object to be applied to the content class or a callable taking - a queryset and spitting out a new one. - - If a filter with the given `key` already exists, the new filter - replaces the old. - """ - if not cls.active_filters: - cls.active_filters = {} - if key is None: - key = filter - cls.active_filters[key] = filter - - def active(self): - """ - Return only currently active objects. - """ - return self.apply_active_filters(self) # ------------------------------------------------------------------------ def path_to_cache_key(path): diff --git a/feincms/utils/managers.py b/feincms/utils/managers.py new file mode 100644 index 000000000..4adee3197 --- /dev/null +++ b/feincms/utils/managers.py @@ -0,0 +1,50 @@ +# ------------------------------------------------------------------------ +class ActiveAwareContentManagerMixin(object): + """ + Implement what's necessary to add some kind of "active" state for content + objects. The notion of active is defined by a number of filter rules that + must all match (AND) for the object to be active. + + A Manager for a content class using the "datepublisher" extension + should either adopt this mixin or implement a similar interface. + """ + + # A dict of filters which are used to determine whether a page is active or not. + # Extended for example in the datepublisher extension (date-based publishing and + # un-publishing of pages) + active_filters = {} + + @classmethod + def apply_active_filters(cls, queryset): + """ + Apply all filters defined to the queryset passed and return the result. + """ + for filt in cls.active_filters.values(): + if callable(filt): + queryset = filt(queryset) + else: + queryset = queryset.filter(filt) + + return queryset + + @classmethod + def add_to_active_filters(cls, filter, key=None): + """ + Add a new clause to the active filters. A filter may be either + a Q object to be applied to the content class or a callable taking + a queryset and spitting out a new one. + + If a filter with the given `key` already exists, the new filter + replaces the old. + """ + if not cls.active_filters: + cls.active_filters = {} + if key is None: + key = filter + cls.active_filters[key] = filter + + def active(self): + """ + Return only currently active objects. + """ + return self.apply_active_filters(self) From ad16411024c07e32d59fcd1fde6cb49542bb8a23 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 11:01:04 +0200 Subject: [PATCH 0055/1590] Point users to south if database schema does not match the code --- feincms/management/checker.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 344bd20e8..627cd9f77 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -47,7 +47,9 @@ def _fn(sender, **kwargs): u'%s.%s' % (field.__class__.__module__, field.__class__.__name__), ) - print style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to find out what the correct column types are.\n' % ( + print style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to' + ' find out what the correct column types are. (Or use south, which is what' + ' you should be doing anyway.)\n' % ( cls._meta.app_label, )) return _fn From 11e8b44e791f7e8cf3fa7a597f86f4d3960b1b1e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 11:41:41 +0200 Subject: [PATCH 0056/1590] TemplateContent: Use template loaders directly, works correctly when the cached loader is activated now --- feincms/content/template/models.py | 91 ++++++++++++++++++------------ 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index efff1d426..c3c38cffd 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -3,44 +3,41 @@ from django import forms from django.conf import settings from django.db import models -from django.template.loader import find_template_loader, render_to_string +from django.template.loader import (Context, Template, TemplateDoesNotExist, + find_template_loader) from django.utils.translation import ugettext_lazy as _ from feincms.admin.editor import ItemEditorForm -def get_templates(): - seen = set() +DEFAULT_TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ) - yield ('', '----------') - for loader in settings.TEMPLATE_LOADERS: - loader_instance = find_template_loader(loader) - if not loader_instance or not hasattr(loader_instance, 'get_template_sources'): - continue +class TemplateChoices(object): + def __init__(self, template_loaders): + self.template_loaders = template_loaders - for basepath in loader_instance.get_template_sources('.'): - path = os.path.join(basepath, 'content', 'template') - try: - templates = os.listdir(path) - except (OSError, IOError): - continue + def __iter__(self): + seen = set() - for template in templates: - if template in seen: - continue - if template[:4] == '.tmp': + for loader in self.template_loaders: + for basepath in loader.get_template_sources('.'): + path = os.path.join(basepath, 'content', 'template') + try: + templates = os.listdir(path) + except (OSError, IOError): continue - seen.add(template) - yield (template, template) - - -class TemplateContentAdminForm(ItemEditorForm): - filename = forms.ChoiceField(label=_('template')) - def __init__(self, *args, **kwargs): - super(TemplateContentAdminForm, self).__init__(*args, **kwargs) - self.fields['filename'].choices = sorted(get_templates(), key=lambda p: p[1]) + for template in templates: + if template in seen: + continue + if template.endswith(('~', '.tmp')): + continue + seen.add(template) + yield (template, template) class TemplateContent(models.Model): @@ -52,19 +49,43 @@ class TemplateContent(models.Model): The templates aren't restricted in any way. """ - feincms_item_editor_form = TemplateContentAdminForm - - filename = models.CharField(_('template'), max_length=100, - choices=()) - class Meta: abstract = True verbose_name = _('template content') verbose_name_plural = _('template contents') + @classmethod + def initialize_type(cls, TEMPLATE_LOADERS=DEFAULT_TEMPLATE_LOADERS): + cls.template_loaders = [find_template_loader(loader) + for loader in TEMPLATE_LOADERS if loader] + + cls.add_to_class('filename', models.CharField(_('template'), max_length=100, + choices=TemplateChoices(cls.template_loaders))) + def render(self, **kwargs): context = kwargs.pop('context', None) + name = 'content/template/%s' % self.filename + + for loader in self.template_loaders: + try: + template, display_name = loader.load_template(name) + except TemplateDoesNotExist: + continue + + if not hasattr(template, 'render'): + template = Template(template, name=name) + + if context: + ctx = context + ctx.update(dict(content=self, **kwargs)) + else: + ctx = Context(dict(content=self, **kwargs)) + + result = template.render(Context(dict(content=self, **kwargs))) + + if context: + context.pop() + + return result - return render_to_string('content/template/%s' % self.filename, dict({ - 'content': self, - }, **kwargs), context_instance=context) + return u'' # Fail? From 8a64658c7a0ff85f107cb268e8d3e24053b66680 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 11:43:53 +0200 Subject: [PATCH 0057/1590] Fix typos in translations extension --- feincms/module/page/extensions/translations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/extensions/translations.py b/feincms/module/page/extensions/translations.py index 9da81c8ec..ee165ff57 100644 --- a/feincms/module/page/extensions/translations.py +++ b/feincms/module/page/extensions/translations.py @@ -109,10 +109,10 @@ def register(cls, admin_cls): )) if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": - cls.register_request_processors(translations_request_processor_explicit, + cls.register_request_processor(translations_request_processor_explicit, key='translations') else: # STANDARD - cls.register_request_processors(translations_request_processor_standard, + cls.register_request_processor(translations_request_processor_standard, key='translations') @monkeypatch_method(cls) From 26106f0226e10d9396abd29df246227dbbf3ffe1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 11:46:26 +0200 Subject: [PATCH 0058/1590] Fix coverage report --- example/settings.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/example/settings.py b/example/settings.py index 95898013e..1104b77cc 100644 --- a/example/settings.py +++ b/example/settings.py @@ -169,12 +169,9 @@ 'feincms.shortcuts', 'feincms.templatetags', 'feincms.templatetags.applicationcontent_tags', - 'feincms.templatetags.feincms_admin_tags', - 'feincms.templatetags.feincms_compat_tags', 'feincms.templatetags.feincms_tags', 'feincms.templatetags.feincms_thumbnail', 'feincms.templatetags.fragment_tags', - 'feincms.templatetags.utils', 'feincms.translations', 'feincms.urls', 'feincms.utils', From 8c7668ce383a87a1665b376c81aa07d83c1f7ddb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 11:48:20 +0200 Subject: [PATCH 0059/1590] Complete the removal of feincms_compat_tags --- docs/api/templatetags.rst | 15 --------------- feincms/templates/admin/feincms/fe_editor.html | 2 +- feincms/templates/admin/feincms/item_editor.html | 2 +- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/docs/api/templatetags.rst b/docs/api/templatetags.rst index a594dd417..8bc98c5e9 100644 --- a/docs/api/templatetags.rst +++ b/docs/api/templatetags.rst @@ -35,18 +35,3 @@ Page-module specific tags .. automodule:: feincms.templatetags.fragment_tags :members: :noindex: - - -Tags not part of the public API -------------------------------- - -These tags aren't guaranteed to stay or to be kept backwards compatible in -any way. They should be considered for internal use only. - -.. automodule:: feincms.templatetags.feincms_admin_tags - :members: - :noindex: - -.. automodule:: feincms.templatetags.feincms_compat_tags - :members: - :noindex: diff --git a/feincms/templates/admin/feincms/fe_editor.html b/feincms/templates/admin/feincms/fe_editor.html index e018cf799..efa99087a 100644 --- a/feincms/templates/admin/feincms/fe_editor.html +++ b/feincms/templates/admin/feincms/fe_editor.html @@ -1,5 +1,5 @@ {% extends "admin/change_form.html" %} -{% load feincms_compat_tags i18n admin_modify adminmedia %} +{% load i18n admin_modify adminmedia %} {% block extrahead %}{{ block.super }} diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index bed8a7993..c60034cd8 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -1,5 +1,5 @@ {% extends "admin/change_form.html" %} -{% load feincms_compat_tags i18n admin_modify adminmedia %} +{% load i18n admin_modify adminmedia %} {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} From 38a62d089ad344b0a972817bcb0ee212c64075d1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 12:14:20 +0200 Subject: [PATCH 0060/1590] Make warnings more useful by pointing out the source of the usage --- feincms/admin/editor.py | 2 +- feincms/content/application/models.py | 2 +- feincms/module/page/models.py | 20 ++++++++++---------- feincms/utils/__init__.py | 4 ++-- feincms/views/base.py | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/feincms/admin/editor.py b/feincms/admin/editor.py index 65afabe3c..aea81e08c 100644 --- a/feincms/admin/editor.py +++ b/feincms/admin/editor.py @@ -2,7 +2,7 @@ warnings.warn("Accessing the item and tree editor through `feincms.admin.editor`" " has been deprecated. Please use `feincms.admin.item_editor` and" " `feincms.admin.tree_editor` instead.", - DeprecationWarning) + DeprecationWarning, stacklevel=2) from feincms.admin.item_editor import ItemEditor, ItemEditorForm from feincms.admin.tree_editor import TreeEditor, ajax_editable_boolean, \ diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 199fede9d..b05e3f46e 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -207,7 +207,7 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, " function or using the 'urlconf/view_name' notation has been deprecated." " Use 'feincms.content.application.models.app_reverse' or the 'app_reverse'" " template tag from 'applicationcontent_tags' directly.", - DeprecationWarning) + DeprecationWarning, stacklevel=2) return app_reverse(other_viewname, other_urlconf, args=args, kwargs=kwargs, prefix=prefix, *vargs, **vkwargs) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 2b1386c80..987f04722 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -85,7 +85,7 @@ def page_for_path(self, path, raise404=False): def page_for_path_or_404(self, path): warnings.warn('page_for_path_or_404 is deprecated. Use page_for_path instead.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) return self.page_for_path(path, raise404=True) def best_match_for_path(self, path, raise404=False): @@ -171,19 +171,19 @@ def for_request(self, request, raise404=False, best_match=False, setup=True): def for_request_or_404(self, request): warnings.warn('for_request_or_404 is deprecated. Use for_request instead.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) return self.for_request(request, raise404=True) def best_match_for_request(self, request, raise404=False): warnings.warn('best_match_for_request is deprecated. Use for_request instead.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) page = self.best_match_for_path(request.path, raise404=raise404) page.setup_request(request) return page def from_request(self, request, best_match=False): warnings.warn('from_request is deprecated. Use for_request instead.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) if hasattr(request, '_feincms_page'): return request._feincms_page @@ -211,7 +211,7 @@ def __get__(self, obj, objtype=None): warnings.warn('Page request and response processors have been moved into ' 'their own module. Accessing them via the Page class will not be possible ' 'in FeinCMS 1.6 anymore.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) return getattr(processors, self.name) def __set__(self, obj, val): @@ -281,7 +281,7 @@ def active_children(self): additionally select only child pages that are active. """ warnings.warn('active_children is deprecated. Use self.children.active() instead.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) return Page.objects.active().filter(parent=self) def active_children_in_navigation(self): @@ -292,7 +292,7 @@ def active_children_in_navigation(self): to disclose). """ warnings.warn('active_children_in_navigation is deprecated. Use self.children.in_navigation() instead.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) return self.active_children().filter(in_navigation=True) def short_title(self): @@ -382,7 +382,7 @@ def get_siblings_and_self(page): As the name says. """ warnings.warn('get_siblings_and_self is deprecated. You probably want self.parent.children.active() anyway.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) return page.get_siblings(include_self=True) def cache_key(self): @@ -486,7 +486,7 @@ def register_request_processors(cls, *processors): warnings.warn("register_request_processors has been deprecated," " use register_request_processor instead.", - DeprecationWarning) + DeprecationWarning, stacklevel=2) for processor in processors: cls.register_request_processor(processor) @@ -501,7 +501,7 @@ def register_response_processors(cls, *processors): warnings.warn("register_response_processors has been deprecated," " use register_response_processor instead.", - DeprecationWarning) + DeprecationWarning, stacklevel=2) for processor in processors: cls.register_response_processor(processor) diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 8294a1d7d..9127c7276 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -83,7 +83,7 @@ def prefilled_attribute(name): " more widely used solutions such as django-queryset-transform" " (bundled as `feincms.utils.queryset_transform`) and" " django-batchselect.", - DeprecationWarning) + DeprecationWarning, stacklevel=2) key = '_prefill_%s' % name @@ -122,7 +122,7 @@ def prefill_entry_list(queryset, *attrs, **kwargs): " more widely used solutions such as django-queryset-transform" " (bundled as `feincms.utils.queryset_transform`) and" " django-batchselect.", - DeprecationWarning) + DeprecationWarning, stacklevel=2) region = kwargs.get('region', None) diff --git a/feincms/views/base.py b/feincms/views/base.py index e1c4737f6..72f6b8081 100644 --- a/feincms/views/base.py +++ b/feincms/views/base.py @@ -2,6 +2,6 @@ warnings.warn('feincms.views.base is deprecated. Please use feincms.views.legacy if ' 'you want to keep on using the old handler. Otherwise, it is advised to switch ' 'to the class-based view (Django >= 1.3 only).', - DeprecationWarning) + DeprecationWarning, stacklevel=2) from feincms.views.legacy.views import * From 056a5ef413638830d7b6e4a40a8ba3d22dda656e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 12:14:40 +0200 Subject: [PATCH 0061/1590] Stop creating warnings without good reasons --- feincms/content/application/models.py | 2 +- feincms/content/template/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index b05e3f46e..8599360e1 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -333,7 +333,7 @@ def save(self, commit=True, *args, **kwargs): cls.feincms_item_editor_form = ApplicationContentItemEditorForm # Make sure the patched reverse() method has all information it needs - cls.parent.field.rel.to.register_request_processors(retrieve_page_information) + cls.parent.field.rel.to.register_request_processor(retrieve_page_information) def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index c3c38cffd..80436a81a 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -7,7 +7,7 @@ find_template_loader) from django.utils.translation import ugettext_lazy as _ -from feincms.admin.editor import ItemEditorForm +from feincms.admin.item_editor import ItemEditorForm DEFAULT_TEMPLATE_LOADERS = ( From f8e3b398702bdd185c90278e729ccd88144b7880 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 12:00:12 +0200 Subject: [PATCH 0062/1590] Make TranslatedObjectMixin translation discovery fully case insensitive --- feincms/translations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/translations.py b/feincms/translations.py index 75f10a87b..bf370877e 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -101,8 +101,8 @@ class TranslatedObjectMixin(object): def _get_translation_object(self, queryset, language_code): try: return queryset.filter( - Q(language_code=language_code) - | Q(language_code=short_language_code(language_code)) + Q(language_code__iexact=language_code) + | Q(language_code__iexact=short_language_code(language_code)) ).order_by('-language_code')[0] except IndexError: try: From 0a615f9e69170f90782c5e20d328d41a9274e62e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 17 Aug 2011 14:38:55 +0200 Subject: [PATCH 0063/1590] TemplateContent: Use correct context instance --- feincms/content/template/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 80436a81a..f82fe4501 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -81,7 +81,7 @@ def render(self, **kwargs): else: ctx = Context(dict(content=self, **kwargs)) - result = template.render(Context(dict(content=self, **kwargs))) + result = template.render(ctx) if context: context.pop() From 2529ab09c97b8c2301a6de29d139a7bd42c94414 Mon Sep 17 00:00:00 2001 From: Mason Hugus Date: Wed, 17 Aug 2011 11:29:39 -0400 Subject: [PATCH 0064/1590] Added optional navigation_extension output to PageSitemap --- feincms/module/page/sitemap.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index ef640bf95..522c2e63c 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -13,7 +13,7 @@ class PageSitemap(Sitemap): The PageSitemap can be used to automatically generate sitemap.xml files for submission to index engines. See http://www.sitemaps.org/ for details. """ - def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset=None, filter=None, *args, **kwargs): + def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset=None, filter=None, extended_navigation=False, *args, **kwargs): """ The PageSitemap accepts the following parameters for customisation of the resulting sitemap.xml output: @@ -28,16 +28,20 @@ def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset in the site map. * filter -- pass in a callable that transforms a queryset to filter out the pages you want to include in the site map. + * extended_navigation -- if set to True, adds pages from any navigation + extensions. If using PagePretender, make sure to include title, url, + level, in_navigation and optionally modification_date. """ super(PageSitemap, self).__init__(*args, **kwargs) - self.depth_cutoff = max_depth - self.navigation_only = navigation_only - self.changefreq = changefreq - self.filter = filter + self.depth_cutoff = max_depth + self.navigation_only = navigation_only + self.changefreq = changefreq + self.filter = filter + self.extended_navigation = extended_navigation if queryset is not None: - self.queryset = queryset + self.queryset = queryset else: - self.queryset = Page.objects.active() + self.queryset = Page.objects.active() def items(self): """ @@ -62,7 +66,15 @@ def items(self): if self.depth_cutoff > 0: qs = qs.filter(level__lte=self.max_depth-1) - return [ p for p in qs if p.is_active() ] + pages = [ p for p in qs if p.is_active() ] + + if self.extended_navigation: + for idx, page in enumerate(pages): + if getattr(page, 'navigation_extension', None): + pages[idx + 1:idx + 1] = page.extended_navigation() + + return pages + def lastmod(self, obj): return getattr(obj, 'modification_date', None) From f0be831f98d54781af1cdea990b7387eb5c9d227 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 18 Aug 2011 12:48:10 +0200 Subject: [PATCH 0065/1590] Use TransformManager for translated objects --- feincms/translations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/translations.py b/feincms/translations.py index bf370877e..334e01cdd 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -37,6 +37,8 @@ class NewsTranslation(Translation(News)): from django.utils import translation from django.utils.translation import ugettext_lazy as _ +from feincms.utils import queryset_transform + def short_language_code(code=None): """ @@ -71,7 +73,7 @@ def is_primary_language(language=None): return language == settings.LANGUAGES[0][0] -class TranslatedObjectManager(models.Manager): +class TranslatedObjectManager(queryset_transform.TransformManager): """ This manager offers convenience methods. """ From f2bdeda117b869675daf26deaaeba80e12280b0a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 18 Aug 2011 13:27:20 +0200 Subject: [PATCH 0066/1590] Replace the postgresql_psycopg2 media library hack with a reusable version for all feincms.translations users --- feincms/module/medialibrary/models.py | 42 ++++------------- feincms/translations.py | 66 ++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 34 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index ffb3fb860..e47385f39 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -26,8 +26,8 @@ from feincms import settings from feincms.models import ExtensionsMixin from feincms.templatetags import feincms_thumbnail -from feincms.translations import TranslatedObjectMixin, Translation, \ - TranslatedObjectManager, admin_translationinline +from feincms.translations import (TranslatedObjectMixin, Translation, + TranslatedObjectManager, admin_translationinline, lookup_translations) # ------------------------------------------------------------------------ class CategoryManager(models.Manager): @@ -144,16 +144,12 @@ def __init__(self, *args, **kwargs): def __unicode__(self): trans = None - # This might be provided using a .extra() clause to avoid hundreds of extra queries: - if hasattr(self, "preferred_translation"): - trans = getattr(self, "preferred_translation", u"") - else: - try: - trans = unicode(self.translation) - except models.ObjectDoesNotExist: - pass - except AttributeError, e: - pass + try: + trans = unicode(self.translation) + except models.ObjectDoesNotExist: + pass + except AttributeError, e: + pass if trans and trans.strip(): return trans @@ -450,27 +446,7 @@ def import_zipfile(request, category_id, data): return HttpResponseRedirect(reverse('admin:medialibrary_mediafile_changelist')) def queryset(self, request): - qs = super(MediaFileAdmin, self).queryset(request) - - # FIXME: This is an ugly hack but it avoids 1-3 queries per *FILE* - # retrieving the translation information - # TODO: This should be adapted to multi-db. - if django_settings.DATABASE_ENGINE == 'postgresql_psycopg2': - qs = qs.extra( - select = { - 'preferred_translation': - """SELECT caption FROM medialibrary_mediafiletranslation - WHERE medialibrary_mediafiletranslation.parent_id = medialibrary_mediafile.id - ORDER BY - language_code = %s DESC, - language_code = %s DESC, - LENGTH(language_code) DESC - LIMIT 1 - """ - }, - select_params = (translation.get_language(), django_settings.LANGUAGE_CODE) - ) - return qs + return super(MediaFileAdmin, self).queryset(request).transform(lookup_translations()) def save_model(self, request, obj, form, change): obj.purge_translation_cache() diff --git a/feincms/translations.py b/feincms/translations.py index 334e01cdd..249d87a00 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -73,6 +73,66 @@ def is_primary_language(language=None): return language == settings.LANGUAGES[0][0] +def lookup_translations(language_code=None): + """ + Pass the return value of this function to .transform() to automatically + resolve translation objects + + The current language is used if ``language_code`` isn't specified. + """ + def _transform(qs): + lang_ = language_code if language_code else translation.get_language() + + instance_dict = {} + + # Don't do anything for those who already have a cached translation available + for instance in qs: + trans = cache.get(instance.get_translation_cache_key(lang_)) + if trans: + instance._cached_translation = trans + else: + instance_dict[instance.pk] = instance + + # We really, really need something in here to continue + if not instance_dict: + return + + candidates = instance_dict.values()[0].translations.model._default_manager.all() + + if instance_dict: + _process(candidates, instance_dict, lang_, 'iexact') + if instance_dict: + _process(candidates, instance_dict, settings.LANGUAGE_CODE, 'istartswith') + if instance_dict: + for candidate in candidates.filter(pk__in=instance_dict.keys()): + if candidate.parent_id in instance_dict: + _found(instance_dict, candidate) + + # No translations for the rest + for instance in instance_dict.values(): + instance._cached_translation = None + + def _found(instance_dict, candidate): + parent = instance_dict[candidate.parent_id] + cache.set(parent.get_translation_cache_key(), candidate) + parent._cached_translation = candidate + candidate.parent = parent + del instance_dict[candidate.parent_id] + + def _process(candidates, instance_dict, lang_, op_): + for candidate in candidates.filter( + Q(pk__in=instance_dict.keys()), + Q(**{'language_code__' + op_: lang_}) + | Q(**{'language_code__' + op_: short_language_code(lang_)}) + ).order_by('-language_code'): + + # The candidate's parent might already have a translation by now + if candidate.parent_id in instance_dict: + _found(instance_dict, candidate) + + return _transform + + class TranslatedObjectManager(queryset_transform.TransformManager): """ This manager offers convenience methods. @@ -150,7 +210,11 @@ def get_translation(self, language_code=None): trans.parent = self return trans - translation = property(get_translation) + @property + def translation(self): + if not hasattr(self, '_cached_translation'): + self._cached_translation = self.get_translation() + return self._cached_translation @property def available_translations(self): From bc7fb8be49f9c11c15e3e8f2ed3eb8c398a06926 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 18 Aug 2011 14:23:41 +0200 Subject: [PATCH 0067/1590] Catch _NoTranslation instances in lookup_translations too --- feincms/translations.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/feincms/translations.py b/feincms/translations.py index 249d87a00..b9f8e261d 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -40,6 +40,13 @@ class NewsTranslation(Translation(News)): from feincms.utils import queryset_transform +class _NoTranslation(object): + """Simple marker for when no translations exist for a certain object + + Only used for caching.""" + pass + + def short_language_code(code=None): """ Extract the short language code from its argument (or return the default language code). @@ -89,7 +96,10 @@ def _transform(qs): for instance in qs: trans = cache.get(instance.get_translation_cache_key(lang_)) if trans: - instance._cached_translation = trans + if trans is _NoTranslation: + instance._cached_translation = None + else: + instance._cached_translation = trans else: instance_dict[instance.pk] = instance @@ -148,13 +158,6 @@ def only_language(self, language=short_language_code): return self.filter(translations__language_code=language) -class _NoTranslation(object): - """Simple marker for when no translations exist for a certain object - - Only used for caching.""" - pass - - class TranslatedObjectMixin(object): """ Mixin with helper methods. From d6d8ec665ece8db2d744186c275ddc1db9709e60 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 18 Aug 2011 17:37:13 +0200 Subject: [PATCH 0068/1590] Disable expand-on-hover in TreeEditor This made drag-drop really hard even for apt mouse-users. --- feincms/static/feincms/fein_tree.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/feincms/static/feincms/fein_tree.js b/feincms/static/feincms/fein_tree.js index 90fa41ab0..99a122301 100755 --- a/feincms/static/feincms/fein_tree.js +++ b/feincms/static/feincms/fein_tree.js @@ -108,19 +108,6 @@ feincms.jQuery(function($){ // check if mouse is over a row if (event.pageY >= top && event.pageY <= top + rowHeight) { - // check if collapsed children, if so, on hover with simple timeout - if( - $('span.page_marker', element).hasClass('children') && - $('span.page_marker', element).hasClass('closed') - ) { - var id = extract_item_id($('span.page_marker', element).attr('id')); - setTimeout(function() { - doToggle(id, true); - $('#result_list tbody').recolorRows(); - $('span.page_marker', element).removeClass('closed'); - }, 750); - } - var targetRow = null; var targetLoc; if(event.pageY >= top && event.pageY <= top + rowHeight / 2 && element.prev()) { From cf4da5b6942288a94e61afce7b849fb37a8c862a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 18 Aug 2011 21:58:05 +0200 Subject: [PATCH 0069/1590] Fix #211: Missing TemplateSyntaxError import Thanks to bbjay for the report. --- feincms/templatetags/applicationcontent_tags.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index e6ff42852..f62b17a1f 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -1,5 +1,6 @@ from django import template from django.core.urlresolvers import NoReverseMatch +from django.template import TemplateSyntaxError from django.template.defaulttags import kwarg_re from django.utils.encoding import smart_str From 80e90cdf478f10a9df02b17b6c89b7374a588ec1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 18 Aug 2011 23:17:54 +0200 Subject: [PATCH 0070/1590] Remove TODO which is not relevant anymore --- feincms/static/feincms/item_editor.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index e6dc07883..871e3dda0 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -190,8 +190,6 @@ if(!Array.indexOf) { if(new_form_count > old_form_count){ return $('#'+modvar+'_set-'+(new_form_count-1)); } - // TODO: add fallback for older versions by manually cloning - // empty fieldset (provided using extra=1) } function set_item_field_value(item, field, value) { From 6bd26e07ac0c1ec94059a3874dfcd67c004c03d4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 20 Aug 2011 13:02:57 +0200 Subject: [PATCH 0071/1590] Fix #213: Remove reference to jquery.color.js which was never used anyway --- feincms/templates/admin/feincms/fe_editor_done.html | 1 - 1 file changed, 1 deletion(-) diff --git a/feincms/templates/admin/feincms/fe_editor_done.html b/feincms/templates/admin/feincms/fe_editor_done.html index 24d9c2fd8..6649593a1 100644 --- a/feincms/templates/admin/feincms/fe_editor_done.html +++ b/feincms/templates/admin/feincms/fe_editor_done.html @@ -5,7 +5,6 @@ {% endif %} - diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py new file mode 100644 index 000000000..34e07ab83 --- /dev/null +++ b/feincms/templatetags/feincms_admin_tags.py @@ -0,0 +1,21 @@ +from django import template + + +register = template.Library() + + +@register.filter +def post_process_fieldsets(fieldset): + """ + Removes a few fields from FeinCMS admin inlines, those being + ``id``, ``DELETE`` and ``ORDER`` currently. + + Additionally, it ensures that dynamically added fields (i.e. + ``ApplicationContent``'s ``admin_fields`` option) works correctly. + """ + + excluded_fields = ('id', 'DELETE', 'ORDER') + fieldset.fields = [f for f in fieldset.form.fields.keys() if f not in excluded_fields] + + for line in fieldset: + yield line From 456515e2048db0ee0ab13cecfba6716e5d0e637d Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 15 Sep 2011 11:44:57 +0200 Subject: [PATCH 0108/1590] Caching: Make sure the cache keys are unique and feincms-namespaced even if several sites share the same memcache. This might cure some very obscure errors I have been getting. --- feincms/module/page/models.py | 5 ++--- feincms/translations.py | 11 ++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index fdda82308..c3f2c0ec4 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -47,13 +47,12 @@ def path_to_cache_key(path): # logic below borrowed from http://richwklein.com/2009/08/04/improving-django-cache-part-ii/ # via acdha's django-sugar - if len(path) > 250: + if len(path) > 220: m = md5() m.update(path) path = m.hexdigest() + '-' + path[:200] - cache_key = 'PAGE-FOR-URL-%d-%s' % ( django_settings.SITE_ID, path ) - + cache_key = 'FEINCMS:%d:PAGE-FOR-URL:%s' % (django_settings.SITE_ID, path) return cache_key class PageManager(models.Manager, ActiveAwareContentManagerMixin): diff --git a/feincms/translations.py b/feincms/translations.py index 5be32aac4..8f13708f4 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -185,11 +185,12 @@ def get_translation_cache_key(self, language_code=None): """Return the cache key used to cache this object's translations so we can purge on-demand""" if not language_code: language_code = translation.get_language() - return '-'.join(['%s' % s for s in - self._meta.db_table, - self.id, - language_code, - ]) + return (('FEINCMS:%d:XLATION:' % settings.SITE_ID) + + '-'.join(['%s' % s for s in + self._meta.db_table, + self.id, + language_code, + ])) def get_translation(self, language_code=None): if not language_code: From 920be48d2f9ae2a48e08742be12abb49c1c42ca2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 15 Sep 2011 12:01:40 +0200 Subject: [PATCH 0109/1590] post_process_fieldsets: Do not flatten fieldsets --- docs/admin.rst | 4 +++ feincms/templatetags/feincms_admin_tags.py | 31 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/admin.rst b/docs/admin.rst index 82128cdb0..6a22fd94a 100644 --- a/docs/admin.rst +++ b/docs/admin.rst @@ -196,6 +196,10 @@ settings on the content type model itself: content type. The custom inline should inherit from ``FeinCMSInline`` or be configured the same way. + If you override ``fieldsets`` you **must** include ``region`` and + ``ordering`` even though they aren't shown in the administration + interface. + Putting it all together ======================= diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py index 34e07ab83..dd306e30c 100644 --- a/feincms/templatetags/feincms_admin_tags.py +++ b/feincms/templatetags/feincms_admin_tags.py @@ -11,11 +11,32 @@ def post_process_fieldsets(fieldset): ``id``, ``DELETE`` and ``ORDER`` currently. Additionally, it ensures that dynamically added fields (i.e. - ``ApplicationContent``'s ``admin_fields`` option) works correctly. + ``ApplicationContent``'s ``admin_fields`` option) are shown. """ - excluded_fields = ('id', 'DELETE', 'ORDER') - fieldset.fields = [f for f in fieldset.form.fields.keys() if f not in excluded_fields] + fields_to_include = set(fieldset.form.fields.keys()) + for f in ('id', 'DELETE', 'ORDER'): + fields_to_include.discard(f) - for line in fieldset: - yield line + def _filter_recursive(fields): + ret = [] + for f in fields: + if hasattr(f, '__iter__'): + # Several fields on one line + sub = _filter_recursive(f) + # Only add if there's at least one field left + if sub: + ret.append(sub) + elif f in fields_to_include: + ret.append(f) + fields_to_include.discard(f) + return ret + + new_fields = _filter_recursive(fieldset.fields) + # Add all other fields (ApplicationContent's admin_fields) to + # the end of the fieldset + for f in fields_to_include: + new_fields.append(f) + + fieldset.fields = new_fields + return fieldset From b48e7e679b10c8a433ef8ff0f12ac87cbfa55e45 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 15 Sep 2011 12:19:55 +0200 Subject: [PATCH 0110/1590] Add minimal parsing of Content-Type header to AppContent's send_directly. AppContent send_directly wrongly assumed Content-Type to be just a text/plain like string, but there are options (like "Content-Type: text/plain; charset=utf8"). --- feincms/content/application/models.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 8205c0eeb..475e38cd7 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -419,8 +419,13 @@ def process(self, request, **kw): return True # successful def send_directly(self, request, response): + mimetype = response.get('Content-Type', 'text/plain') + if ';' in mimetype: + mimetype = mimetype.split(';')[0] + mimetype = mimetype.strip() + return (response.status_code != 200 or request.is_ajax() or getattr(response, 'standalone', False) or - response['Content-Type'] not in ('text/html', 'text/plain')) + mimetype not in ('text/html', 'text/plain')) def render(self, **kwargs): return getattr(self, 'rendered_result', u'') From b4a93eeb72c966137bbbb338c34d54328ffbf4d9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 15 Sep 2011 18:21:59 +0200 Subject: [PATCH 0111/1590] Add a test for ApplicationContent's admin_fields feature --- tests/tests.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index a69b05bc7..32eb34f6c 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1229,6 +1229,10 @@ def test_25_applicationcontent(self): self.assertEqual(reverse('tests.testapp.blog_urls/blog_entry_list'), '/test-page/test-child-page/') self.assertEqual(reverse('whatever/ac_module_root'), '/test-page/') + # Ensure ApplicationContent's admin_fields support works properly + self.assertContains(self.client.get('/admin/page/page/%d/' % page.id), + 'exclusive_subpages') + def test_26_page_form_initial(self): self.create_default_page_set() From 30f80034f3da358e83a20fe225569902decec9ca Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 16 Sep 2011 10:12:28 +0200 Subject: [PATCH 0112/1590] Move translations extension into main extensions folder --- .../{page => }/extensions/translations.py | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) rename feincms/module/{page => }/extensions/translations.py (84%) diff --git a/feincms/module/page/extensions/translations.py b/feincms/module/extensions/translations.py similarity index 84% rename from feincms/module/page/extensions/translations.py rename to feincms/module/extensions/translations.py index ee165ff57..3d5f3df19 100644 --- a/feincms/module/page/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -108,30 +108,32 @@ def register(cls, admin_cls): help_text=_('Leave this empty for entries in the primary language.') )) - if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": - cls.register_request_processor(translations_request_processor_explicit, - key='translations') - else: # STANDARD - cls.register_request_processor(translations_request_processor_standard, - key='translations') - - @monkeypatch_method(cls) - def get_redirect_to_target(self, request): - """ - Find an acceptable redirect target. If this is a local link, then try - to find the page this redirect references and translate it according - to the user's language. This way, one can easily implement a localized - "/"-url to welcome page redirection. - """ - target = self.redirect_to - if target and target.find('//') == -1: # Not an offsite link http://bla/blubb - try: - page = cls.objects.page_for_path(target) - page = page.get_translation(getattr(request, 'LANGUAGE_CODE', None)) - target = page.get_absolute_url() - except cls.DoesNotExist: - pass - return target + if hasattr(cls, 'register_request_processor'): + if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": + cls.register_request_processor(translations_request_processor_explicit, + key='translations') + else: # STANDARD + cls.register_request_processor(translations_request_processor_standard, + key='translations') + + if hasattr(cls, 'get_redirect_to_target'): + @monkeypatch_method(cls) + def get_redirect_to_target(self, request): + """ + Find an acceptable redirect target. If this is a local link, then try + to find the page this redirect references and translate it according + to the user's language. This way, one can easily implement a localized + "/"-url to welcome page redirection. + """ + target = self.redirect_to + if target and target.find('//') == -1: # Not an offsite link http://bla/blubb + try: + page = cls.objects.page_for_path(target) + page = page.get_translation(getattr(request, 'LANGUAGE_CODE', None)) + target = page.get_absolute_url() + except cls.DoesNotExist: + pass + return target @monkeypatch_method(cls) def available_translations(self): From a5478863a4f5f30e04ecb89673d2c918e96825c3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 16 Sep 2011 10:13:32 +0200 Subject: [PATCH 0113/1590] datepublisher might be usable for other base models too --- feincms/module/{page => }/extensions/datepublisher.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename feincms/module/{page => }/extensions/datepublisher.py (100%) diff --git a/feincms/module/page/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py similarity index 100% rename from feincms/module/page/extensions/datepublisher.py rename to feincms/module/extensions/datepublisher.py From f637d750329125f19215769cb6bca69a4aa1cc6c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 20 Sep 2011 15:50:57 +0200 Subject: [PATCH 0114/1590] New application content features made this rewrite unavoidable --- docs/integration.rst | 301 ++++++++++++++++++++++-------------------- docs/templatetags.rst | 32 ++++- 2 files changed, 190 insertions(+), 143 deletions(-) diff --git a/docs/integration.rst b/docs/integration.rst index 174910119..b92d58770 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -53,11 +53,11 @@ contains definitions for both. If you want to provide your own view, it's your responsability to create correct URLconf entries. -Generic views -============= +Generic and custom views +======================== If you use FeinCMS to manage your site, chances are that you still want -to use generic views for certain parts. You probably still need a +to use generic and/or custom views for certain parts. You probably still need a ``feincms_page`` object inside your template to generate the navigation and render regions not managed by the generic views. The best way to ensure the presence of a ``feincms_page`` instance in the template context is @@ -70,34 +70,11 @@ to add ``feincms.context_processors.add_page_if_missing`` to your Integrating 3rd party apps ========================== -The :class:`~feincms.content.application.models.ApplicationContent` will -help you with this. - -# TODO rewrite this section - -The plugin/content type needs a URLconf and uses resolve and a patched -reverse to integrate the application into the CMS. The advantages are -that there is no modification of the ROOT_URLCONF necessary when -moving the integration point for the 3rd party application around. On -the downside, the application's template has less control over the -base template and views inside the 3rd party app cannot be reversed -from outside the ApplicationContent renderer. The bigger flexibility -in choosing the integration point comes with a cost when it comes to -rendering the content from the 3rd party app. - -.. warning:: - - The monkey patch for ``django.core.urlresolvers.reverse`` contained - in the ``ApplicationContent`` code has to happen "early enough". If - ``reverse`` is unable to determine URLs for views integrated through - ``ApplicationContent`` you have to move the application content code - import to an earlier place (f.e. on the first line of your main - ``models.py`` or even in your ``urls.py`` (barring circular import - problems). - - This might change if we find a better way to solve this or if - Django allows us to poke deeper into the URL resolving/reversing - machinery. +Third party apps such as django-registration can be integrated in the CMS +too. :class:`~feincms.content.application.models.ApplicationContent` lets you +delegate a subset of your page tree to a third party application. The only +thing you need is specifying a URLconf file which is used to determine which +pages exist below the integration point. Adapting the 3rd party application for FeinCMS @@ -120,178 +97,220 @@ can be too easily violated. An example ``urls.py`` follows:: - from django.conf.urls.defaults import * + from django.conf.urls.defaults import patterns, include, url + from django.views.generic.detail import DetailView + from django.views.generic.list import ListView from news.models import Entry - entry_dict = {'queryset': Entry.objects.all()} urlpatterns = patterns('', - url(r'^$', - 'django.views.generic.list_detail.object_list', - entry_dict, - name='entry_list'), - url(r'^(?P\d{4})/(?P\d{2})/(?P\d{2})/(?P[^/]+)/', - 'django.views.generic.date_based.object_detail', - dict(entry_dict, **{'date_field': 'published_date', 'month_format': '%m', 'slug_field': 'slug'}), - name='entry_detail'), + url(r'^$', ListView.as_view( + queryset=Entry.objects.all(), + ), name='entry_list'), + url(r'^(?P[^/]+)/$', DetailView.as_view( + queryset=Entry.objects.all(), + ), name='entry_detail'), ) +Please note that you should not add the ``news/`` prefix here. You should +*not* reference this ``urls.py`` file anywhere in a ``include`` statement. -Please note that you should not add the ``news/`` prefix here unless -you know exactly what you are doing. Furthermore, this ``urls.py`` is -incomplete -- for a real world implementation, you'd need to add yearly, -monthly and daily archive views too. Furthermore, you should *not* include -this ``urls.py`` file anywhere accessible from your ``ROOT_URLCONF``. -If you write your view methods yourself instead of using generic views, you -should not construct whole response objects, but return the content as a unicode -string. It does not hurt to encapsulate the content inside a response object, -it's simply not worth it because the application content will have to extract -the content from the response and throw the response object away anyway. +Registering the 3rd party application with FeinCMS' ``ApplicationContent`` +-------------------------------------------------------------------------- + +It's as simple as that:: + + from feincms.content.application.models import ApplicationContent + from feincms.module.page.models import Page + + Page.create_content_type(ApplicationContent, APPLICATIONS=( + ('news.urls', 'News application'), + )) + + +Writing the models +------------------ + +Because the URLconf entries ``entry_list`` and ``entry_detail`` aren't +reachable through standard means (remember, they aren't ``include``d +anywhere) it's not possible to use standard ``reverse`` calls to determine +the absolute URL of a news entry. FeinCMS provides its own ``app_reverse`` +function and ``permalink`` decorator mimicking the interface of Django's +standard functionality:: -The :class:`~feincms.content.application.models.ApplicationContent` patches -the standard Django ``reverse`` function, so that ``reverse`` and the -``{% url %}`` template tag works as expected inside the application -content render method. Therefore, :meth:`News.get_absolute_url` is -absolutely standard. ``models.py``:: - from datetime import datetime from django.db import models + from feincms.content.application import models as app_models class Entry(models.Model): - published_date = models.DateField() title = models.CharField(max_length=200) slug = models.SlugField() description = models.TextField(blank=True) class Meta: - get_latest_by = 'published_date' - ordering = ['-published_date'] + ordering = ['-id'] def __unicode__(self): return self.title - @models.permalink + @app_models.permalink def get_absolute_url(self): - return ('entry_detail', (), { - 'year': self.published_date.strftime('%Y'), - 'month': self.published_date.strftime('%m'), - 'day': self.published_date.strftime('%d'), + return ('entry_detail', 'news.urls', (), { 'slug': self.slug, }) -Writing the templates for the application ------------------------------------------ +The only difference is that you do not only have to specify the view name +(``entry_detail``) but also the URLconf file (``news.urls``) for this +specific ``permalink`` decorator. The URLconf string must correspond to the +specification used in the ``APPLICATIONS`` list in the ``create_content_type`` +call. -Nothing special here. The only thing you have to avoid is adding ```` or -```` tags and such, because you're only rendering content for a single -content block, not the whole page. An example ``news/entry_detail.html`` follows:: +.. note:: -
-

{{ object.title }}

- {{ object.published_date|date:"d.m.Y" }} + Previous FeinCMS versions only provided a monkey patched ``reverse`` + method with a slightly different syntax for reversing URLs. This + behavior is still available and as of now (FeinCMS 1.5) still active + by default. It is recommended to start using the new way right now + and add ``FEINCMS_REVERSE_MONKEY_PATCH = False`` to your settings file. - {{ object.description|linebreaks }} -
-And an example ``news/entry_list.html``:: +Returning content from views +---------------------------- - {% for entry in object_list %} -
- {% ifchanged %}
{{ entry.published_date|date:"d.m.Y" }}
{% endifchanged %} -

{{ entry.title }}

-
- {% endfor %} +Three different types of return values can be handled by the application +content code: +* Unicode data (i.e. the return value of ``render_to_string``) +* ``HttpResponse`` instances +* A tuple consisting of two elements: A template instance, template name or list + and a context ``dict``. More on this later under + :ref:`integration-applicationcontent-inheritance20` -Registering and integrating the 3rd party application ------------------------------------------------------ -First, you need to create the content type:: +Unicode data is inserted verbatim into the output. ``HttpResponse`` instances +are returned directly to the client under the following circumstances: - from feincms.content.application.models import ApplicationContent - from feincms.module.page.models import Page +* The HTTP status code differs from ``200 OK`` (Please note that 404 errors may + be ignored if more than one content type with a ``process`` method exists on + the current CMS page.) +* The resource was requested by ``XmlHttpRequest`` (that is, ``request.is_ajax`` + returns ``True``) +* The response was explicitly marked as ``standalone`` by the + :func:`feincms.views.decorators.standalone` view decorator +* The mimetype of the response was not ``text/plain`` or ``text/html`` - Page.create_content_type(ApplicationContent, APPLICATIONS=( - ('news.urls', 'News application'), - )) +Otherwise, the content of the response is unpacked and inserted into the +CMS output as unicode data as if the view returned the content directly, not +wrapped into a ``HttpResponse`` instance. + +If you want to customize this behavior, provide your own subclass of +``ApplicationContent`` with an overridden ``send_directly`` method. The +described behavior is only a sane default and might not fit everyone's +use case. -Your base template does not have to be structured differently just because -you are using application contents now. You must use the bundled FeinCMS -template tags though, because the application content needs the request -object:: +.. note:: - {% extends "base.html" %} + The string or response returned should not contain ```` or ```` + tags because this would invalidate the HTML code returned by FeinCMS. - {% load feincms_tags %} - {% block content %} - {% feincms_render_region feincms_page "main" request %} - {% endblock %} +.. _integration-applicationcontent-inheritance20: -Please note that this necessitates the use of -``django.core.context_processors.request``:: +Letting the application content use the full power of Django's template inheritance +----------------------------------------------------------------------------------- + +If returning a simple unicode string is not enough and you'd like to modify +different blocks in the base template, you have to ensure two things: + +* Use the class-based page handler. This is already the default if you include + ``feincms.urls`` or ``feincms.views.cbv.urls``. +* Make sure your application views use the third return value type described + above: A tuple consisting of a template and a context ``dict``. + +The news application views would then look as follows. Please note the absence +of any template rendering calls: + +``views.py``:: + + from django.shortcuts import get_object_or_404 + from news.models import Entry + + def entry_list(request): + # TODO add pagination here + return 'news/entry_list.html', {'object_list': Entry.objects.all()} + + def entry_detail(request, slug): + return 'news/entry_detail', {'object': get_object_or_404(Entry, slug=slug)} - TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.core.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', - 'django.core.context_processors.request', +``urls.py``:: + + from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('news.views', + url(r'^$', 'entry_list', name='entry_list'), + url(r'^(?P[^/]+)/$', 'entry_detail', name='entry_detail'), ) -The 3rd party application might know how to handle more than one URL (the example -news application does). These subpages won't necessarily exist as page instances -in the tree, the standard view knows how to handle this case. +The two templates referenced, ``news/entry_list.html`` and +``news/entry_detail.html``, should now extend a base template. The recommended +notation is as follows:: + {% extends feincms_page.template.path|default:"base.html" %} -.. _integration-applicationcontent-morecontrol: + {% block ... %} + {# more content snipped #} -Letting the application content control more than one region in the parent template ------------------------------------------------------------------------------------ -The output of the third party app is not strictly constrained to the region; -you can pass additional fragments around, for example to extend the page title -with content from the 3rd party application. Suppose we'd like to add the news -title to the title tag. Add the following lines to your ``news/entry_detail.html``:: +This ensures that the the selected CMS template is still used when rendering +content. - {% load applicationcontent_tags %} - {% fragment request "title" %}{{ object.translation.title }} - {% endfragment %} +.. note:: + + Older versions of FeinCMS only offered fragments for a similar purpose. They + are still suported, but it's recommended you switch over to this style instead. + +.. warning:: + + If you add two application content blocks on the same page and both use this + mechanism, the later 'wins'. -And read the fragment inside your base template:: - {% extends "base.html" %} +More on reversing URLs +---------------------- - {% load applicationcontent_tags feincms_page_tags %} +Application content-aware URL reversing is available both for Python and +Django template code. - {% block title %}{% get_fragment request "title" %} - {{ feincms_page.title }} - {{ block.super }}{% endblock %} +The function works almost like Django's own ``reverse()`` method except +that it resolves URLs from application contents. The second argument, +``urlconf``, has to correspond to the URLconf parameter passed in the +``APPLICATIONS`` list to ``Page.create_content_type``:: - {% block content %} - {% feincms_render_region feincms_page "main" request %} - {% endblock %} + app_reverse('mymodel-detail', 'myapp.urls', args=...) +or:: -Returning responses from the embedded application without wrapping them inside the CMS template ------------------------------------------------------------------------------------------------ + app_reverse('mymodel-detail', 'myapp.urls', kwargs=...) -If the 3rd party application returns a response with status code different from -200, the standard view :func:`feincms.views.base.handler` returns -the response verbatim. The same is true if the 3rd party application returns -a response and ``request.is_ajax()`` is ``True`` or if the application content -returns a HttpResponse with the ``standalone`` attribute set to True. -For example, an application can return an non-html export file -- in that case -you don't really want the CMS to decorate the data file with the web html templates:: +The template tag has to be loaded from the ``applicationcontent_tags`` +template tag library first:: - from feincms.views.decorators import standalone + {% load applicationcontent_tags %} + {% app_reverse "mymodel_detail" "myapp.urls" arg1 arg2 %} - @standalone - def my_view(request): - ... - xls_data = ... whatever ... - return HttpResponse(xls_data, content_type="application/msexcel") +or:: + + {% load applicationcontent_tags %} + {% app_reverse "mymodel_detail" "myapp.urls" name1=value1 name2=value2 %} + +Storing the URL in a context variable is supported too:: + + {% load applicationcontent_tags %} + {% app_reverse "mymodel_detail" "myapp.urls" arg1 arg2 as url %} Additional customization possibilities diff --git a/docs/templatetags.rst b/docs/templatetags.rst index 9a190da7b..9a6f8f8c4 100644 --- a/docs/templatetags.rst +++ b/docs/templatetags.rst @@ -98,7 +98,7 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: .. function:: siblings_along_path_to: This is a filter designed to work in close conjuction with the - ``feincms_navigation`` template tag describe above to build a + ``feincms_navigation`` template tag describe above to build a navigation tree following the path to the current page. Example:: @@ -214,7 +214,35 @@ Application content template tags .. module:: feincms.templatetags.applicationcontent_tags: +.. function:: app_reverse: + + Returns an absolute URL for applications integrated with ApplicationContent + + The tag mostly works the same way as Django's own {% url %} tag:: + + {% load applicationcontent_tags %} + {% app_reverse "mymodel_detail" "myapp.urls" arg1 arg2 %} + + or:: + + {% load applicationcontent_tags %} + {% app_reverse "mymodel_detail" "myapp.urls" name1=value1 name2=value2 %} + + The first argument is a path to a view. The second argument is the URLconf + under which this app is known to the ApplicationContent. + + Other arguments are space-separated values that will be filled in place of + positional and keyword arguments in the URL. Don't mix positional and + keyword arguments. + + If you want to store the URL in a variable instead of showing it right away + you can do so too:: + + {% app_reverse "mymodel_detail" "myapp.urls" arg1 arg2 as url %} + + .. function:: fragment: .. function:: get_fragment: - See :ref:`integration-applicationcontent-morecontrol`. + Don't use those, read up on :ref:`integration-applicationcontent-inheritance20` + instead. From dd8618f3539bad4c1c2e5fad3be1cae804f48b62 Mon Sep 17 00:00:00 2001 From: Urs Breton Date: Tue, 20 Sep 2011 17:00:33 +0200 Subject: [PATCH 0115/1590] fixed linking of django and django-mptt --- quickstart.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/quickstart.sh b/quickstart.sh index 72a928521..f94b8dfac 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -5,8 +5,13 @@ echo "Downloading Django and django-mptt via git... (this will take some time)" -git clone git://github.com/django/django.git django -git clone git://github.com/django-mptt/django-mptt.git mptt +mkdir lib +cd lib +git clone git://github.com/django/django.git +git clone git://github.com/django-mptt/django-mptt.git +cd .. +ln -s lib/django/django django +ln -s lib/django-mptt/mptt mptt cat < Date: Tue, 20 Sep 2011 17:06:30 +0200 Subject: [PATCH 0116/1590] added QUICKSTART.rst instructions --- QUICKSTART.rst | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 QUICKSTART.rst diff --git a/QUICKSTART.rst b/QUICKSTART.rst new file mode 100644 index 000000000..073794e49 --- /dev/null +++ b/QUICKSTART.rst @@ -0,0 +1,72 @@ +======================================== +Setup FeinCMS in less than five minutes +======================================== + +Quickstart +=============== + +* Clone FeinCMS from github (https://github.com/feincms/feincms) into your desired development directory: + +me@machine:~/projects$ git clone git://github.com/feincms/feincms.git + +Now you find a directory named 'feincms' in your development directory. This is your project directory. Feel free to change its name: + +:: +me@machine:~/projects$ mv feincms/ myFeinCMSSite + +Now you can choose between the quickstart variant which takes about a minute (depending on your network connection) or the manual setup, which is as easy as the quickstart variant, but let's you understand what your doing. if you are doing this the first time choose the manual variant, as it's taking you only a minute longer. + + +Manual Setup Variant +-------------------- + +* Create a directory named 'lib' in your development folder and clone the django-mptt module (https://github.com/django-mptt/django-mptt) into it + +:: +me@machine:~/projects$ mkdir lib +me@machine:~/projects$ cd lib +me@machine:~/projects/lib$ git clone git://github.com/feincms/feincms.git + +* Change into your project root and create a symbolic link to the downloaded mptt module + +:: +me@machine:~/projects/lib$ cd ../myFeinCMSSite/ +me@machine:~/projects/myFeinCMSSite$ ln -s ../lib/django-mptt/mptt/ mptt + +* Step into the example app and start the runserver + +:: +me@machine:~/projects/myFeinCMSSite$ cd example +me@machine:~/projects/myFeinCMSSite/example$ ./manage.py runserver + +* The username and password for the examples admin-interface are 'username' and 'password' + + +Quickstart Variant +----------------- + +* Change into your project folder and run the setup script + +:: +me@machine:~/projects$ cd myFeinCMSSite +me@machine:~/projects/myFeinCMSSite$ ./quickstart.sh + +* Wait while django and mptt are being fetched and then follow the on-screen instructions to start the runserver and enjoy the installation + +:: +me@machine:~/projects/myFeinCMSSite$ cd example +me@machine:~/projects/myFeinCMSSite/example$ ./manage.py runserver + +* The username and password for the examples admin-interface are 'username' and 'password' + +Further Steps +=============== + +Feel free to delete all files you do not need for your installation: + +/docs/ +/MANIFEST.in +/quickstart.sh +/setup.py +/tests/ + From f2012a8ba7077fc01599e3ea8898e3363ebe9636 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 20 Sep 2011 17:06:35 +0200 Subject: [PATCH 0117/1590] Small contributions are contributions too --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 0ccb2a826..70ffbeafd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -46,3 +46,4 @@ The authors of FeinCMS are: * Denis Martinez * Silvan Spross * Tobias Haffner +* Urs Breton From 5541ed10d435403d5adf966f7c11ae7a50702c4b Mon Sep 17 00:00:00 2001 From: Urs Breton Date: Tue, 20 Sep 2011 17:10:56 +0200 Subject: [PATCH 0118/1590] edited formatting --- QUICKSTART.rst | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/QUICKSTART.rst b/QUICKSTART.rst index 073794e49..2e1916acb 100644 --- a/QUICKSTART.rst +++ b/QUICKSTART.rst @@ -5,14 +5,13 @@ Setup FeinCMS in less than five minutes Quickstart =============== -* Clone FeinCMS from github (https://github.com/feincms/feincms) into your desired development directory: +Clone FeinCMS from github (https://github.com/feincms/feincms) into your desired development directory: me@machine:~/projects$ git clone git://github.com/feincms/feincms.git Now you find a directory named 'feincms' in your development directory. This is your project directory. Feel free to change its name: -:: -me@machine:~/projects$ mv feincms/ myFeinCMSSite +$ mv feincms/ myFeinCMSSite Now you can choose between the quickstart variant which takes about a minute (depending on your network connection) or the manual setup, which is as easy as the quickstart variant, but let's you understand what your doing. if you are doing this the first time choose the manual variant, as it's taking you only a minute longer. @@ -20,44 +19,39 @@ Now you can choose between the quickstart variant which takes about a minute (de Manual Setup Variant -------------------- -* Create a directory named 'lib' in your development folder and clone the django-mptt module (https://github.com/django-mptt/django-mptt) into it +Create a directory named 'lib' in your development folder and clone the django-mptt module (https://github.com/django-mptt/django-mptt) into it -:: -me@machine:~/projects$ mkdir lib -me@machine:~/projects$ cd lib -me@machine:~/projects/lib$ git clone git://github.com/feincms/feincms.git +$ mkdir lib +$ cd lib +$ git clone git://github.com/feincms/feincms.git -* Change into your project root and create a symbolic link to the downloaded mptt module +Change into your project root and create a symbolic link to the downloaded mptt module -:: -me@machine:~/projects/lib$ cd ../myFeinCMSSite/ -me@machine:~/projects/myFeinCMSSite$ ln -s ../lib/django-mptt/mptt/ mptt +$ cd ../myFeinCMSSite/ +$ ln -s ../lib/django-mptt/mptt/ mptt -* Step into the example app and start the runserver +Step into the example app and start the runserver -:: -me@machine:~/projects/myFeinCMSSite$ cd example -me@machine:~/projects/myFeinCMSSite/example$ ./manage.py runserver +$ cd example +$ ./manage.py runserver -* The username and password for the examples admin-interface are 'username' and 'password' +The username and password for the examples admin-interface are 'username' and 'password' Quickstart Variant ----------------- -* Change into your project folder and run the setup script +Change into your project folder and run the setup script -:: -me@machine:~/projects$ cd myFeinCMSSite -me@machine:~/projects/myFeinCMSSite$ ./quickstart.sh +$ cd myFeinCMSSite +$ ./quickstart.sh -* Wait while django and mptt are being fetched and then follow the on-screen instructions to start the runserver and enjoy the installation +Wait while django and mptt are being fetched and then follow the on-screen instructions to start the runserver and enjoy the installation -:: -me@machine:~/projects/myFeinCMSSite$ cd example -me@machine:~/projects/myFeinCMSSite/example$ ./manage.py runserver +$ cd example +$ ./manage.py runserver -* The username and password for the examples admin-interface are 'username' and 'password' +The username and password for the examples admin-interface are 'username' and 'password' Further Steps =============== From a045999be4953b581dae058358da674bbc8c6177 Mon Sep 17 00:00:00 2001 From: Urs Breton Date: Tue, 20 Sep 2011 17:10:56 +0200 Subject: [PATCH 0119/1590] edited formatting of quickstart linked QUICKSTART.rst with README --- QUICKSTART.rst | 58 +++++++++++++++++++++++++++++--------------------- README.rst | 5 +++++ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/QUICKSTART.rst b/QUICKSTART.rst index 073794e49..495e7e32f 100644 --- a/QUICKSTART.rst +++ b/QUICKSTART.rst @@ -5,65 +5,75 @@ Setup FeinCMS in less than five minutes Quickstart =============== -* Clone FeinCMS from github (https://github.com/feincms/feincms) into your desired development directory: +Clone FeinCMS from github (https://github.com/feincms/feincms) into your desired development directory: -me@machine:~/projects$ git clone git://github.com/feincms/feincms.git +:: + + $ git clone git://github.com/feincms/feincms.git Now you find a directory named 'feincms' in your development directory. This is your project directory. Feel free to change its name: :: -me@machine:~/projects$ mv feincms/ myFeinCMSSite + + $ mv feincms/ myFeinCMSSite Now you can choose between the quickstart variant which takes about a minute (depending on your network connection) or the manual setup, which is as easy as the quickstart variant, but let's you understand what your doing. if you are doing this the first time choose the manual variant, as it's taking you only a minute longer. Manual Setup Variant --------------------- +--------------------- -* Create a directory named 'lib' in your development folder and clone the django-mptt module (https://github.com/django-mptt/django-mptt) into it +Create a directory named 'lib' in your development folder and clone the django-mptt module (https://github.com/django-mptt/django-mptt) into it :: -me@machine:~/projects$ mkdir lib -me@machine:~/projects$ cd lib -me@machine:~/projects/lib$ git clone git://github.com/feincms/feincms.git -* Change into your project root and create a symbolic link to the downloaded mptt module + $ mkdir lib + $ cd lib + $ git clone git://github.com/feincms/feincms.git + +Change into your project root and create a symbolic link to the downloaded mptt module :: -me@machine:~/projects/lib$ cd ../myFeinCMSSite/ -me@machine:~/projects/myFeinCMSSite$ ln -s ../lib/django-mptt/mptt/ mptt -* Step into the example app and start the runserver + $ cd ../myFeinCMSSite/ + $ ln -s ../lib/django-mptt/mptt/ mptt + +Step into the example app and start the runserver :: -me@machine:~/projects/myFeinCMSSite$ cd example -me@machine:~/projects/myFeinCMSSite/example$ ./manage.py runserver -* The username and password for the examples admin-interface are 'username' and 'password' + $ cd example + $ ./manage.py runserver + +The username and password for the examples admin-interface are 'username' and 'password' Quickstart Variant ------------------ +------------------- -* Change into your project folder and run the setup script +Change into your project folder and run the setup script :: -me@machine:~/projects$ cd myFeinCMSSite -me@machine:~/projects/myFeinCMSSite$ ./quickstart.sh -* Wait while django and mptt are being fetched and then follow the on-screen instructions to start the runserver and enjoy the installation + $ cd myFeinCMSSite + $ ./quickstart.sh + +Wait while django and mptt are being fetched and then follow the on-screen instructions to start the runserver and enjoy the installation :: -me@machine:~/projects/myFeinCMSSite$ cd example -me@machine:~/projects/myFeinCMSSite/example$ ./manage.py runserver -* The username and password for the examples admin-interface are 'username' and 'password' + $ cd example + $ ./manage.py runserver + +The username and password for the examples admin-interface are 'username' and 'password' Further Steps -=============== +------------------- Feel free to delete all files you do not need for your installation: +:: + /docs/ /MANIFEST.in /quickstart.sh diff --git a/README.rst b/README.rst index 03016ef3a..524368aa8 100644 --- a/README.rst +++ b/README.rst @@ -77,6 +77,11 @@ Visit these sites * See the google groups page at http://groups.google.com/group/django-feincms * FeinCMS on github: https://github.com/feincms/feincms/ +Quickstart +---------- + +You can find a short quickstart guide at QUICKSTART.rst + Optional Packages ----------------- From 16fae97d240c9296a082598869f46a836daefa28 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 21 Sep 2011 09:23:44 +0200 Subject: [PATCH 0120/1590] Try to import PIL in either of the two ways it can end up installed Fixes #219. --- feincms/module/medialibrary/models.py | 6 +++++- feincms/templatetags/feincms_thumbnail.py | 12 ++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index ffb3fb860..e40c1487c 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -6,7 +6,11 @@ import logging import os import re -from PIL import Image +# Try to import PIL in either of the two ways it can end up installed. +try: + from PIL import Image +except ImportError: + import Image from django import forms from django.contrib import admin, messages diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 8c1a59961..81ce4f718 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -1,12 +1,16 @@ import os from cStringIO import StringIO +# Try to import PIL in either of the two ways it can end up installed. try: from PIL import Image except ImportError: - # Django seems to silently swallow the ImportError under certain - # circumstances. Raise a generic exception explaining why we are - # unable to proceed. - raise Exception, 'FeinCMS requires PIL to be installed' + try: + import Image + except ImportError: + # Django seems to silently swallow the ImportError under certain + # circumstances. Raise a generic exception explaining why we are + # unable to proceed. + raise Exception, 'FeinCMS requires PIL to be installed' from django import template from django.conf import settings From d41fa0538c1f0032fcd2e74a14595123069840ed Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 23 Sep 2011 15:56:33 +0200 Subject: [PATCH 0121/1590] TemplateContent: Optimisation (No need to build an intermediate list to create an iterator, instead just return a generator). --- feincms/content/template/models.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 8cfe81c97..be58454bb 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -22,7 +22,6 @@ def __init__(self, template_loaders): def __iter__(self): seen = set() - choices = [] for loader in self.template_loaders: for basepath in loader.get_template_sources('.'): @@ -38,9 +37,8 @@ def __iter__(self): if template.endswith(('~', '.tmp')): continue seen.add(template) - choices.append((template, template)) - return iter(sorted(choices)) + return ((t, t) for t in sorted(seen)) class TemplateContent(models.Model): From c34347d38307daf5dfc6bfd3243fb8c8779e5766 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 23 Sep 2011 17:18:55 +0200 Subject: [PATCH 0122/1590] More TemplateContent documentation. --- docs/contenttypes.rst | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 07b866315..df795f9bd 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -446,11 +446,18 @@ Template content .. module:: feincms.content.table.template .. class:: TemplateContent() -This content scans all template directories for templates below +This is a content type that just includes a snippet from a template. +This content type scans all template directories for templates below ``content/template/`` and allows the user to select one of these templates -which are rendered using the Django template language. +which are then rendered using the Django template language. -Template usage isn't restricted in any way. +Note that some file extensions are automatically filtered so they won't +appear in the list, namely anything that matches *.~ and *.tmp will be +ignored. + +Also note that a template content is not sandboxed or specially rendered. +Whatever a django template can do a TemplateContent snippet can do too, +so be careful whom you grant write permissions. Video inclusion code for youtube, vimeo etc. From f2de708a09f8b6cf4fdbca6b3583747b6ebbc2e2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 26 Sep 2011 11:04:55 +0200 Subject: [PATCH 0123/1590] Flush all Meta _caches by enumerating them ... hopefully fixing a Heisenbug which has been filling my mailbox over the last days. --- feincms/models.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 7850d1361..95214c6a2 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -744,11 +744,13 @@ class Meta(feincms_content_base.Meta): # Here we flush the caches rather than actually _filling them so # that relations defined after all content types registrations # don't miss out. - for attr in dir(cls._meta): - if attr.startswith('_fill_') and attr.endswith('_cache'): - cache_name = attr[len('_fill'):] - if hasattr(cls._meta, cache_name): - delattr(cls._meta, cache_name) + for cache_name in ('_field_cache', '_field_name_cache', '_m2m_cache', + '_related_objects_cache', '_related_many_to_many_cache', + '_name_map'): + try: + delattr(cls._meta, cache_name) + except AttributeError: + pass return new_type From d34df0b7e8ebf4254dee4c9547f4d62ae84b9712 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 27 Sep 2011 09:31:49 +0200 Subject: [PATCH 0124/1590] Prefer path_info to path when querying pages to allow FeinCMS installations in subfolders --- feincms/module/page/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c3f2c0ec4..311903515 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -157,10 +157,12 @@ def for_request(self, request, raise404=False, best_match=False, setup=True): """ if not hasattr(request, '_feincms_page'): + path = request.path_info or request.path + if best_match: - request._feincms_page = self.best_match_for_path(request.path, raise404=raise404) + request._feincms_page = self.best_match_for_path(path, raise404=raise404) else: - request._feincms_page = self.page_for_path(request.path, raise404=raise404) + request._feincms_page = self.page_for_path(path, raise404=raise404) if setup: request._feincms_page.setup_request(request) From 1ec8f1e7484706cdd60c8caf3925a2598052e6b4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 28 Sep 2011 13:18:57 +0200 Subject: [PATCH 0125/1590] Use the sledge hammer to make sure no Model._meta instance contains stale data --- feincms/__init__.py | 21 ++++++++++++++++++--- feincms/models.py | 17 ----------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index d26357e96..9eb6ecf39 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -39,9 +39,24 @@ def ensure_completely_loaded(): if COMPLETELY_LOADED: return True - from django.core.management.validation import get_validation_errors - from StringIO import StringIO - get_validation_errors(StringIO(), None) + # Ensure meta information concerning related fields is up-to-date. + # Upon accessing the related fields information from Model._meta, + # the related fields are cached and never refreshed again (because + # models and model relations are defined upon import time, if you + # do not fumble around with models like we do in FeinCMS.) + # + # Here we flush the caches rather than actually _filling them so + # that relations defined after all content types registrations + # don't miss out. + from django.db.models import loading + for model in loading.get_models(): + for cache_name in ('_field_cache', '_field_name_cache', '_m2m_cache', + '_related_objects_cache', '_related_many_to_many_cache', + '_name_map'): + try: + delattr(model._meta, cache_name) + except AttributeError: + pass COMPLETELY_LOADED = True return True diff --git a/feincms/models.py b/feincms/models.py index 95214c6a2..daafebc71 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -735,23 +735,6 @@ class Meta(feincms_content_base.Meta): for key, includes in model.feincms_item_editor_includes.items(): cls.feincms_item_editor_includes.setdefault(key, set()).update(includes) - # Ensure meta information concerning related fields is up-to-date. - # Upon accessing the related fields information from Model._meta, - # the related fields are cached and never refreshed again (because - # models and model relations are defined upon import time, if you - # do not fumble around with models like we do right here.) - # - # Here we flush the caches rather than actually _filling them so - # that relations defined after all content types registrations - # don't miss out. - for cache_name in ('_field_cache', '_field_name_cache', '_m2m_cache', - '_related_objects_cache', '_related_many_to_many_cache', - '_name_map'): - try: - delattr(cls._meta, cache_name) - except AttributeError: - pass - return new_type @property From 10a7ea33309ec58e6ea24108c13941d5a6784caf Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 28 Sep 2011 13:31:18 +0200 Subject: [PATCH 0126/1590] Fix tests for recent path_info change --- tests/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 32eb34f6c..4b06c4a0b 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -988,7 +988,7 @@ def test_19_page_manager(self): self.assertRaises(Page.DoesNotExist, lambda: Page.objects.page_for_path('/asdf/')) request = Empty() - request.path = page.get_absolute_url() + request.path = request.path_info = page.get_absolute_url() request.method = 'GET' request.get_full_path = lambda: '/xyz/' request.GET = {} @@ -1346,7 +1346,7 @@ def test_30_context_processors(self): request.GET = {} request.META = {} request.method = 'GET' - request.path = '/test-page/test-child-page/abcdef/' + request.path = request.path_info = '/test-page/test-child-page/abcdef/' request.get_full_path = lambda: '/test-page/test-child-page/abcdef/' ctx = add_page_if_missing(request) From 8f115983d892c83d306e75c5580db8669d872b85 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 28 Sep 2011 13:31:32 +0200 Subject: [PATCH 0127/1590] Commit additional late-added relations tests --- tests/tests.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 4b06c4a0b..5541e93f5 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -203,11 +203,23 @@ def test_09_related_objects_cache(self): related models have been defined. """ class Attachment(models.Model): - base = models.ForeignKey(ExampleCMSBase) + base = models.ForeignKey(ExampleCMSBase, related_name='test_related_name') related_models = map( lambda x: x.model, ExampleCMSBase._meta.get_all_related_objects()) + self.assertTrue(Attachment in related_models) + self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) + #self.assertFalse(hasattr(Attachment, 'anycontents')) + + class AnyContent(models.Model): + attachment = models.ForeignKey(Attachment, related_name='anycontents') + class Meta: + abstract = True + ct = ExampleCMSBase.create_content_type(AnyContent) + + self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) + self.assertTrue(hasattr(Attachment, 'anycontents')) Page.register_extensions('datepublisher', 'navigation', 'seo', 'symlinks', From dbd3838c6eb98f5f9fdca9e50bbe8a56b9b3a724 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 3 Oct 2011 16:51:58 +0200 Subject: [PATCH 0128/1590] Better fix for issue addressed in 67c275837a1b13cbd985b80f0cf5ca32a0763d48 Explicitely raise a 404 if we have a redirect and extra path info instead of just continuing and hope someone else notices. This would give seemingly empty pages on redirect pages plus something. --- feincms/module/page/processors.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index e90f828d8..779b4a6e0 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -14,11 +14,11 @@ def require_path_active_request_processor(page, request): def redirect_request_processor(page, request): - if request._feincms_extra_context.get('extra_path', '/') == '/': - target = page.get_redirect_to_target(request) - if target: + target = page.get_redirect_to_target(request) + if target: + if request._feincms_extra_context.get('extra_path', '/') == '/': return HttpResponseRedirect(target) - + raise Http404() def frontendediting_request_processor(page, request): if not 'frontend_editing' in request.GET: From 4dcbced80939296189b93b4688ce08f876fee11b Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 3 Oct 2011 16:59:58 +0200 Subject: [PATCH 0129/1590] Fix tests broken by d34df0b7e8ebf4254dee4c9547f4d62ae84b9712: need a path_info attribute on mock requests too. --- tests/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 32eb34f6c..4b06c4a0b 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -988,7 +988,7 @@ def test_19_page_manager(self): self.assertRaises(Page.DoesNotExist, lambda: Page.objects.page_for_path('/asdf/')) request = Empty() - request.path = page.get_absolute_url() + request.path = request.path_info = page.get_absolute_url() request.method = 'GET' request.get_full_path = lambda: '/xyz/' request.GET = {} @@ -1346,7 +1346,7 @@ def test_30_context_processors(self): request.GET = {} request.META = {} request.method = 'GET' - request.path = '/test-page/test-child-page/abcdef/' + request.path = request.path_info = '/test-page/test-child-page/abcdef/' request.get_full_path = lambda: '/test-page/test-child-page/abcdef/' ctx = add_page_if_missing(request) From 11405c22f7bc1e6fc9631e2942f6e5532f6471d9 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 3 Oct 2011 17:28:15 +0200 Subject: [PATCH 0130/1590] Add test for another redirect-with-junk-path. We want to get a 404 no matter what FEINCMS_ALLOW_EXTRA_PATH is set to. --- tests/tests.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index 4b06c4a0b..1b0efa949 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1430,6 +1430,27 @@ def test_34_access(self): r = self.client.get('/foo/') self.assertEquals(r.status_code, 404) + + def test_35_access_with_extra_path(self): + self.login() + self.create_page(title='redirect again', override_url='/', redirect_to='/somewhere/', active=True) + self.create_page(title='somewhere', active=True) + + r = self.client.get('/') + self.assertRedirects(r, '/somewhere/') + r = self.client.get('/dingdong/') + self.assertEquals(r.status_code, 404) + + old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH + feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True + + r = self.client.get('/') + self.assertRedirects(r, '/somewhere/') + r = self.client.get('/dingdong/') + self.assertEquals(r.status_code, 404) + + feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old + Entry.register_extensions('seo', 'translations', 'seo', 'ct_tracker') class BlogTestCase(TestCase): def setUp(self): From 6db5017a53a4b4b37675d79d79e76baf04c4a12c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 5 Oct 2011 16:52:57 +0200 Subject: [PATCH 0131/1590] Add support for a channel URL to VideoContent (yet stupid, but works) --- feincms/content/video/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index f8bf0f93d..b679bcba1 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -12,10 +12,12 @@ class VideoContent(models.Model): Other portals aren't supported currently, but would be easy to add if anyone would take up the baton. + + You should probably use feincms-oembed. """ PORTALS = ( - ('youtube', re.compile(r'youtube'), lambda url: {'v': re.search(r'[?&]v=([^#&]+)', url).group(1)}), + ('youtube', re.compile(r'youtube'), lambda url: {'v': re.search(r'([?&]v=|./././)([^#&]+)', url).group(2)}), ('vimeo', re.compile(r'vimeo'), lambda url: {'id': re.search(r'/(\d+)', url).group(1)}), ('sf', re.compile(r'sf\.tv'), lambda url: {'id': re.search(r'/([a-z0-9\-]+)', url).group(1)}), ) From 716c4ca85fac10cf4e60bda28b3326c40a8c092b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 10 Oct 2011 15:40:27 +0200 Subject: [PATCH 0132/1590] Thumbnail filters: Fix handling of image formats --- feincms/templatetags/feincms_thumbnail.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 56247dac2..2945c1645 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -89,11 +89,12 @@ def generate(self, storage, original, size, miniature): # defining the size w, h = int(size['w']), int(size['h']) + format = image.format # Save format for the save() call later image.thumbnail([w, h], Image.ANTIALIAS) buf = StringIO() if image.mode not in ('RGBA', 'RGB', 'L'): image = image.convert('RGBA') - image.save(buf, image.format or 'jpeg', quality=100) + image.save(buf, format or 'jpeg', quality=100) raw_data = buf.getvalue() buf.close() storage.save(miniature, ContentFile(raw_data)) @@ -135,13 +136,14 @@ def generate(self, storage, original, size, miniature): x_offset = 0 y_offset = float(src_height - crop_height) * y / 100 + format = image.format # Save format for the save() call later image = image.crop((x_offset, y_offset, x_offset+int(crop_width), y_offset+int(crop_height))) image = image.resize((dst_width, dst_height), Image.ANTIALIAS) buf = StringIO() if image.mode not in ('RGBA', 'RGB', 'L'): image = image.convert('RGBA') - image.save(buf, image.format or 'jpeg', quality=100) + image.save(buf, format or 'jpeg', quality=100) raw_data = buf.getvalue() buf.close() storage.save(miniature, ContentFile(raw_data)) From 4fd641a08c855dfc59fc7f044e1afcc5f57341d7 Mon Sep 17 00:00:00 2001 From: tayg Date: Tue, 11 Oct 2011 00:34:09 +0300 Subject: [PATCH 0133/1590] Moved inline instances generating into appropriate inherited method. Old behaviour is broken due to the recent changes in Django. See https://github.com/django/django/commit/d297bc7b9da8e929e781e708234777d98348476a#django/contrib/admin/options.py --- feincms/admin/item_editor.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index d48df6f0b..eb8aaf9b0 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -61,11 +61,15 @@ def __init__(self, model, admin_site): ensure_completely_loaded() super(ItemEditor, self).__init__(model, admin_site) - - # Add inline instances for FeinCMS content inlines - for inline_class in self.get_feincms_inlines(model): + + def get_inline_instances(self, request): + inline_instances = super(ItemEditor, self).get_inline_instances(request) + + for inline_class in self.get_feincms_inlines(self.model): inline_instance = inline_class(self.model, self.admin_site) - self.inline_instances.append(inline_instance) + inline_instances.append(inline_instance) + + return inline_instances def get_feincms_inlines(self, model): """ Generate genuine django inlines for registered content types. """ From 849dc156a647e0d776f0e3a18596935aee59edc8 Mon Sep 17 00:00:00 2001 From: tayg Date: Tue, 11 Oct 2011 18:52:28 +0300 Subject: [PATCH 0134/1590] Added condition to retain capability to work regardless of Django version. Common functionality for both variants is factored out into method. --- feincms/admin/item_editor.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index eb8aaf9b0..3f19c0ef3 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -61,15 +61,24 @@ def __init__(self, model, admin_site): ensure_completely_loaded() super(ItemEditor, self).__init__(model, admin_site) + + if hasattr(self, 'inline_instances'): + # Add inline instances for FeinCMS content inlines + # This works in Django 1.3 and lower + # In Django 1.4 inline instances are generated using overridden get_inline_instances() + self.append_feincms_inlines(self.inline_instances) def get_inline_instances(self, request): inline_instances = super(ItemEditor, self).get_inline_instances(request) + self.append_feincms_inlines(inline_instances) + return inline_instances + + def append_feincms_inlines(self, inline_instances): + """ Append generated FeinCMS content inlines to native django inlines. """ for inline_class in self.get_feincms_inlines(self.model): inline_instance = inline_class(self.model, self.admin_site) inline_instances.append(inline_instance) - - return inline_instances def get_feincms_inlines(self, model): """ Generate genuine django inlines for registered content types. """ From 03ab5d11da768070482f6ae2180cca46a2f57199 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 12 Oct 2011 13:11:35 +0200 Subject: [PATCH 0135/1590] Itemeditor styling: Don't hardcode region tab height and make background color match background image. This allows for adding icons or better style the region tabs. --- feincms/static/feincms/style.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/static/feincms/style.css b/feincms/static/feincms/style.css index adc3cf488..273564e1e 100644 --- a/feincms/static/feincms/style.css +++ b/feincms/static/feincms/style.css @@ -10,19 +10,19 @@ border-bottom:none; min-width:100px; margin-top:3px; - height:13px; + /* height:13px; */ font-weight: bold; font-size: 12px; background-image:none; color: #333333; - background: #eee url(img/nav-bg.gif) top repeat-x; + background: #E1E1E1 url(img/nav-bg.gif) top repeat-x; } .tab_active { margin-top: 0; padding-top: 6px; padding-bottom: 7px; - background-image:url('img/default-bg.gif'); - color: #ffffff; + background: #7BA0C6 url('img/default-bg.gif') top repeat-x; + color: white; } #main { From d28da849dee90811d0466056115b1c4caa3ff993 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 14 Oct 2011 00:52:06 +0200 Subject: [PATCH 0136/1590] Remove unused argument --- feincms/views/cbv/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 005355354..0e5d8ca04 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -17,7 +17,7 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): return self.handler(request, *args, **kwargs) - def handler(self, request, path=None, *args, **kwargs): + def handler(self, request, *args, **kwargs): self.page = Page.objects.for_request(request, raise404=True, best_match=True, setup=False) response = self.prepare() if response: From 50444c68b5c8301dcd3bba3db0197c63bc58b223 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 14 Oct 2011 01:05:15 +0200 Subject: [PATCH 0137/1590] Add new setting variable to define 404 error page inside the CMS and adapt page handler appropriately --- feincms/default_settings.py | 12 +++++++++++- feincms/views/cbv/views.py | 23 ++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index bd0b48943..a3790e1ab 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -91,10 +91,20 @@ #: Name of the tidy function - anything which takes (html) and returns (html, errors, warnings) can be used: FEINCMS_TIDY_FUNCTION = getattr(settings, 'FEINCMS_TIDY_FUNCTION', 'feincms.utils.html.tidy.tidy_html') - # ------------------------------------------------------------------------ #: Monkey-patch django.core.urlresvolers.reverse to be application-content aware? #: (The monkey patch is deprecated and should not be used anymore. Use the #: ``app_reverse`` function and the ``{% app_reverse %}`` template tag instead.) #: The value of this setting will be changed to False in FeinCMS 1.6. FEINCMS_REVERSE_MONKEY_PATCH = getattr(settings, 'FEINCMS_REVERSE_MONKEY_PATCH', True) + +# ------------------------------------------------------------------------ +#: Makes the page handling mechanism try to find a cms page with that +#: path if it encounters a page not found situation. This allows for nice +#: customised cms-styled error pages. Do not go overboard, this should +#: be as simple and as error resistant as possible, so refrain from +#: deeply nested error pages or advanced content types. + +FEINCMS_CMS_404_PAGE = getattr(settings, 'FEINCMS_CMS_404_PAGE', None) + +# ------------------------------------------------------------------------ diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 0e5d8ca04..84de54104 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -7,7 +7,7 @@ from feincms.module.page.models import Page -class Handler(TemplateView): +class HandlerBase(TemplateView): """ Class-based handler for FeinCMS page content """ @@ -98,3 +98,24 @@ def __name__(self): This property is used by django-debug-toolbar """ return self.__class__.__name__ + +# ------------------------------------------------------------------------ +class Handler(HandlerBase): + def handler(self, request, *args, **kwargs): + try: + return super(Handler, self).handler(request, *args, **kwargs) + except Http404, e: + if settings.FEINCMS_CMS_404_PAGE: + try: + http404 = e + request.original_path_info = request.path_info + request.path_info = settings.FEINCMS_CMS_404_PAGE + return super(Handler, self).handler(request, *args, **kwargs) + except Http404, e: + raise e + else: + raise + +# ------------------------------------------------------------------------ + + From e8f3a9a6d05cabef02e31579a3a16718b3c54936 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 14 Oct 2011 01:08:43 +0200 Subject: [PATCH 0138/1590] Re-raise original exception when 404-page not found --- feincms/views/cbv/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 84de54104..3cc92628c 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -111,7 +111,7 @@ def handler(self, request, *args, **kwargs): request.original_path_info = request.path_info request.path_info = settings.FEINCMS_CMS_404_PAGE return super(Handler, self).handler(request, *args, **kwargs) - except Http404, e: + except Http404: raise e else: raise From 019bba499569bb22035fa858026d476bd9ae29dd Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 14 Oct 2011 01:17:41 +0200 Subject: [PATCH 0139/1590] Use relative imports --- feincms/views/cbv/urls.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/views/cbv/urls.py b/feincms/views/cbv/urls.py index 45cc0f818..8024afe14 100644 --- a/feincms/views/cbv/urls.py +++ b/feincms/views/cbv/urls.py @@ -1,6 +1,9 @@ + +from __future__ import absolute_import + from django.conf.urls.defaults import patterns, include, url -from feincms.views.cbv.views import Handler +from .views import Handler handler = Handler.as_view() urlpatterns = patterns('', From c3ef6d08d8301e9f8ce3fc2d55f24e56c2df5394 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 14 Oct 2011 01:18:04 +0200 Subject: [PATCH 0140/1590] Import cbv.urls instead of just repeating what's there --- feincms/urls.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/feincms/urls.py b/feincms/urls.py index 45cc0f818..a5281796f 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -1,9 +1,4 @@ -from django.conf.urls.defaults import patterns, include, url -from feincms.views.cbv.views import Handler -handler = Handler.as_view() +from __future__ import absolute_import -urlpatterns = patterns('', - url(r'^$', handler, name='feincms_home'), - url(r'^(.*)/$', handler, name='feincms_handler'), -) +from .views.cbv.urls import * From 25ddd518f7907f01dd6b79312762ddc3d671f9d1 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 14 Oct 2011 01:24:45 +0200 Subject: [PATCH 0141/1590] Fudge in-cms 404 page to also return http status code 404 --- feincms/views/cbv/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 3cc92628c..54455a37e 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -110,7 +110,9 @@ def handler(self, request, *args, **kwargs): http404 = e request.original_path_info = request.path_info request.path_info = settings.FEINCMS_CMS_404_PAGE - return super(Handler, self).handler(request, *args, **kwargs) + response = super(Handler, self).handler(request, *args, **kwargs) + response.status_code = 404 + return response except Http404: raise e else: From 10d3c19764453d17ecd1c5f8a71947926eb6d36f Mon Sep 17 00:00:00 2001 From: Kwizda Prod User Date: Fri, 14 Oct 2011 10:59:45 +0200 Subject: [PATCH 0142/1590] django-reversion automatically does some registering if you just import it, so don't do that if not explicitely asked for. This would cause strange problems when deleting users on a site that doesn't use reversion but reversion is available, like on some shared host providers. --- feincms/models.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index daafebc71..8e92b02f0 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -24,11 +24,6 @@ from feincms import settings, ensure_completely_loaded from feincms.utils import get_object, copy_model_instance -try: - import reversion -except ImportError: - reversion = None - try: any except NameError: @@ -805,8 +800,11 @@ def replace_content_with(self, obj): @classmethod def register_with_reversion(cls): - if not reversion: + try: + import reversion + except ImportError: raise EnvironmentError("django-reversion is not installed") + follow = [] for content_type_model in cls._feincms_content_types: related_manager = "%s_set" % content_type_model.__name__.lower() From a8e4434bf6ac54ebf0cd3127d0f52b738e55f846 Mon Sep 17 00:00:00 2001 From: Psyton Date: Sun, 16 Oct 2011 09:22:02 +0700 Subject: [PATCH 0143/1590] Some fixes for russian translation --- feincms/locale/ru/LC_MESSAGES/django.po | 99 +++++++++++-------------- 1 file changed, 45 insertions(+), 54 deletions(-) diff --git a/feincms/locale/ru/LC_MESSAGES/django.po b/feincms/locale/ru/LC_MESSAGES/django.po index 1549e957f..beb3a59c8 100644 --- a/feincms/locale/ru/LC_MESSAGES/django.po +++ b/feincms/locale/ru/LC_MESSAGES/django.po @@ -157,12 +157,12 @@ msgstr "(без подписи)" #: content/section/models.py:48 module/medialibrary/fields.py:45 #: module/medialibrary/models.py:102 msgid "media file" -msgstr "" +msgstr "медиа файл" #: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 #: module/medialibrary/models.py:103 msgid "media files" -msgstr "" +msgstr "медиа файлы" #: content/medialibrary/models.py:131 msgid "block" @@ -282,14 +282,12 @@ msgid "data" msgstr "данные" #: content/template/models.py:62 -#, fuzzy msgid "template content" -msgstr "шаблон" +msgstr "содержимое шаблона" #: content/template/models.py:63 -#, fuzzy msgid "template contents" -msgstr "шаблон" +msgstr "содержимое шаблона" #: content/video/models.py:23 msgid "video link" @@ -365,39 +363,36 @@ msgid "modification date" msgstr "дата изменения" #: module/extensions/ct_tracker.py:134 -#, fuzzy msgid "content types" -msgstr "содержание" +msgstr "содержимое" #: module/extensions/featured.py:9 -#, fuzzy msgid "featured" msgstr "создан" #: module/extensions/featured.py:14 -#, fuzzy msgid "Featured" msgstr "создан" #: module/extensions/seo.py:9 msgid "meta keywords" -msgstr "" +msgstr "ключевые слова" #: module/extensions/seo.py:10 msgid "This will be prepended to the default keyword list." -msgstr "" +msgstr "Будет добавлено к основному списку ключевых слов" #: module/extensions/seo.py:11 msgid "meta description" -msgstr "" +msgstr "описание" #: module/extensions/seo.py:12 msgid "This will be prepended to the default description." -msgstr "" +msgstr "Будет добавлено к основному описанию" #: module/extensions/seo.py:18 msgid "Search engine optimization" -msgstr "" +msgstr "Оптимизация для поисковых систем" #: module/medialibrary/models.py:51 msgid "parent" @@ -432,7 +427,6 @@ msgid "file size" msgstr "размер файла" #: module/medialibrary/models.py:203 -#, fuzzy msgid "file info" msgstr "файл" @@ -461,7 +455,6 @@ msgid "Text" msgstr "Текст" #: module/medialibrary/models.py:286 -#, fuzzy msgid "Rich Text" msgstr "Текст" @@ -515,7 +508,7 @@ msgstr[2] "" #: module/medialibrary/models.py:373 msgid "Add selected media files to category" -msgstr "" +msgstr "Добавить выбранные файлы в категорию" #: module/medialibrary/models.py:440 #, python-format @@ -525,11 +518,11 @@ msgstr "" #: module/medialibrary/models.py:442 #, python-format msgid "ZIP file invalid: %s" -msgstr "" +msgstr "не корректный архив" #: module/medialibrary/models.py:448 msgid "No input file given" -msgstr "" +msgstr "не заданы файлы" #: module/page/models.py:256 msgid "active" @@ -541,7 +534,7 @@ msgstr "в навигации" #: module/page/models.py:264 msgid "override URL" -msgstr "" +msgstr "перекрыть адрес" #: module/page/models.py:265 msgid "" @@ -556,7 +549,7 @@ msgstr "редирект на" #: module/page/models.py:267 msgid "Target URL for automatic redirects." -msgstr "" +msgstr "Адрес для автоматического перенаправления" #: module/page/models.py:268 msgid "Cached URL" @@ -571,7 +564,6 @@ msgid "pages" msgstr "страницы" #: module/page/models.py:297 module/page/models.py:782 -#, fuzzy msgid "is active" msgstr "активная" @@ -589,15 +581,15 @@ msgstr "Другие параметры" #: module/page/models.py:721 msgid "Add child page" -msgstr "" +msgstr "Добавить дочернюю страницу" #: module/page/models.py:723 msgid "View on site" -msgstr "" +msgstr "Посмотреть на сайте" #: module/page/models.py:759 msgid "You don't have the necessary permissions to edit this object" -msgstr "" +msgstr "У вас нет прад для редактирования объекта" #: module/page/models.py:774 msgid "inherited" @@ -621,11 +613,11 @@ msgstr "Оставьте поле пустым, если запись должн #: module/page/extensions/datepublisher.py:78 msgid "visible from - to" -msgstr "" +msgstr "видима с - по" #: module/page/extensions/datepublisher.py:88 msgid "Date-based publishing" -msgstr "" +msgstr "Публикация основанная на дате" #: module/page/extensions/excerpt.py:9 msgid "excerpt" @@ -642,49 +634,49 @@ msgstr "" #: module/page/extensions/navigation.py:77 #: module/page/extensions/navigation.py:97 msgid "navigation extension" -msgstr "" +msgstr "расширение навигации" #: module/page/extensions/navigation.py:99 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" +msgstr "Выберите модуль, расширяющий навигацию по дочерним страницам" #: module/page/extensions/navigation.py:112 msgid "Navigation extension" -msgstr "" +msgstr "Расширение навигации" #: module/page/extensions/relatedpages.py:13 msgid "Select pages that should be listed as related content." -msgstr "" +msgstr "Выбертие страницу, которая будет показана в списке связанных страниц" #: module/page/extensions/relatedpages.py:20 msgid "Related pages" -msgstr "" +msgstr "Связанные страницы" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Сайт" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" -msgstr "" +msgstr "Страница-ссылка" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "" +msgstr "Все содержимое будет взято с этой страницы." #: module/page/extensions/symlinks.py:30 msgid "Symlinked page" -msgstr "" +msgstr "Страница-ссылка" #: module/page/extensions/titles.py:13 msgid "content title" -msgstr "" +msgstr "Заголовок содержимого" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" +msgstr "ПЕрвая строка - основной заголовок, остальное - подзаголовоки" #: module/page/extensions/titles.py:15 msgid "page title" @@ -756,7 +748,7 @@ msgstr "Точно сменить шаблон?
Все изменения msgid "" "Really change template?
All changes are saved and content from " "%(source_regions)s is moved to %(target_region)s." -msgstr "" +msgstr "Вы действительно хотите изменить шаблон?
Все сохраненные изменение и содержимое региона %(source_regions)s будут перенесены в %(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -786,7 +778,7 @@ msgstr "Регион пуст" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" +msgstr "Содержимое родительского элемента автоматически наследуется. Для перекрытия этого поведение нужно добавить содержимое." #: templates/admin/feincms/content_editor.html:23 msgid "Add new item" @@ -834,24 +826,24 @@ msgstr "" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Для восстановления этой версии нажмите сохранить." #: templates/admin/feincms/revision_form.html:14 msgid "History" -msgstr "" +msgstr "История" #: templates/admin/feincms/revision_form.html:15 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Отменить %(verbose_name)s" #: templates/admin/feincms/revision_form.html:28 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Для возврата к этой версии нажмите сохранить." #: templates/admin/feincms/tree_editor.html:37 msgid "Shortcuts" -msgstr "" +msgstr "Ярлыки" #: templates/admin/feincms/tree_editor.html:39 msgid "Collapse tree" @@ -863,7 +855,7 @@ msgstr "Развернуть дерево" #: templates/admin/feincms/tree_editor.html:43 msgid "Filter" -msgstr "" +msgstr "Фильтр" #: templates/admin/feincms/page/page/item_editor.html:9 msgid "Edit on site" @@ -871,29 +863,28 @@ msgstr "Редактировать на сайте" #: templates/admin/feincms/page/page/item_editor.html:20 msgid "Add" -msgstr "" +msgstr "Добавить" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "" +msgstr "Добавить меди файлы в категорию" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "" +msgstr "Выбертие категорию:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" +msgstr "Следующие файлы будут добавлены в выбранную категорию:" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "категория" +msgstr "Добавить в категорию" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "Отменить" #: templates/admin/medialibrary/mediafile/change_list.html:12 msgid "Bulk upload a ZIP file:" From 8d52adf1952a204487b14a7c34c176d74671f224 Mon Sep 17 00:00:00 2001 From: Psyton Date: Sun, 16 Oct 2011 09:29:08 +0700 Subject: [PATCH 0144/1590] typo fixes --- feincms/locale/ru/LC_MESSAGES/django.po | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/feincms/locale/ru/LC_MESSAGES/django.po b/feincms/locale/ru/LC_MESSAGES/django.po index beb3a59c8..d2cf43330 100644 --- a/feincms/locale/ru/LC_MESSAGES/django.po +++ b/feincms/locale/ru/LC_MESSAGES/django.po @@ -460,7 +460,7 @@ msgstr "Текст" #: module/medialibrary/models.py:287 msgid "Zip archive" -msgstr "" +msgstr "Zip-архив" #: module/medialibrary/models.py:288 msgid "Microsoft Word" @@ -593,7 +593,7 @@ msgstr "У вас нет прад для редактирования объек #: module/page/models.py:774 msgid "inherited" -msgstr "" +msgstr "унаследовано" #: module/page/models.py:778 msgid "extensions" @@ -822,7 +822,7 @@ msgstr "Начало" #: templates/admin/feincms/recover_form.html:10 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Восстановить %(verbose_name)s" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." @@ -868,11 +868,11 @@ msgstr "Добавить" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "Добавить меди файлы в категорию" +msgstr "Добавить медиа файлы в категорию" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "Выбертие категорию:" +msgstr "Выберите категорию:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" From cd3640291c59ef5b9631a12967ebbfc5a661fefe Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 18 Oct 2011 15:34:33 +0200 Subject: [PATCH 0145/1590] Indicate where the deprecation warning came from --- feincms/content/medialibrary/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 9c05c6811..0b5c13f20 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -91,7 +91,7 @@ class Meta: def initialize_type(cls, POSITION_CHOICES=None, MEDIAFILE_CLASS=MediaFile): warnings.warn('feincms.content.medialibrary.models.MediaFileContent is deprecated.' ' Use feincms.content.medialibrary.v2.MediaFileContent instead.', - DeprecationWarning) + DeprecationWarning, stacklevel=2) if 'feincms.module.medialibrary' not in settings.INSTALLED_APPS: raise ImproperlyConfigured, 'You have to add \'feincms.module.medialibrary\' to your INSTALLED_APPS before creating a %s' % cls.__name__ From 5cdb75f29028def69d3690b1c903f4e077b42b70 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 18 Oct 2011 15:36:26 +0200 Subject: [PATCH 0146/1590] MediaFileContent admin: Show categories with full path in dropdowns, automatically intuit a caption for bulk uploads --- feincms/module/medialibrary/models.py | 21 ++++++++++++++++--- .../medialibrary/mediafile/change_list.html | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index b965c8e6b..545e55896 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -75,15 +75,23 @@ def save(self, *args, **kwargs): super(Category, self).save(*args, **kwargs) + def path_list(self): + if self.parent is None: + return [ self ] + p = self.parent.path_list() + p.append(self) + return p + + def path(self): + return ' - '.join((f.title for f in self.path_list())) class CategoryAdmin(admin.ModelAdmin): - list_display = ['parent', 'title'] + list_display = ['path'] list_filter = ['parent'] list_per_page = 25 search_fields = ['title'] prepopulated_fields = { 'slug': ('title',), } - # ------------------------------------------------------------------------ class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): """ @@ -401,7 +409,7 @@ def get_urls(self): def changelist_view(self, request, extra_context=None): if extra_context is None: extra_context = {} - extra_context['categories'] = Category.objects.all() + extra_context['categories'] = Category.objects.order_by('title') return super(MediaFileAdmin, self).changelist_view(request, extra_context=extra_context) @staticmethod @@ -436,8 +444,15 @@ def import_zipfile(request, category_id, data): mf = MediaFile() mf.file.save(target_fname, ContentFile(z.read(zi.filename))) mf.save() + if category: mf.categories.add(category) + + mt = MediaFileTranslation() + mt.parent = mf + mt.caption = fname.replace('_', ' ') + mt.save() + count += 1 messages.info(request, _("%d files imported") % count) diff --git a/feincms/templates/admin/medialibrary/mediafile/change_list.html b/feincms/templates/admin/medialibrary/mediafile/change_list.html index a6d484b73..d551513e9 100644 --- a/feincms/templates/admin/medialibrary/mediafile/change_list.html +++ b/feincms/templates/admin/medialibrary/mediafile/change_list.html @@ -15,7 +15,7 @@ From cf8563264e7c53b21bb4dc60da206ba460671f1b Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 20 Oct 2011 12:37:19 +0200 Subject: [PATCH 0147/1590] Remove FEINCMS_USE_CACHE, it really doesn't serve any meaningful purpose --- feincms/default_settings.py | 5 ----- feincms/module/page/models.py | 17 +++++++---------- tests/tests.py | 1 - 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index a3790e1ab..46215a2cc 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -62,11 +62,6 @@ # ------------------------------------------------------------------------ # Various settings -# ------------------------------------------------------------------------ -#: Enable caching intermediate results in feincms. Be aware that this might deliver -#: slightly out of date pages if you are not using the 'changedate' page extension. -FEINCMS_USE_CACHE = getattr(settings, 'FEINCMS_USE_CACHE', False) - # ------------------------------------------------------------------------ #: Allow random gunk after a valid page? FEINCMS_ALLOW_EXTRA_PATH = getattr(settings, 'FEINCMS_ALLOW_EXTRA_PATH', False) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 311903515..50ec4ac9b 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -106,11 +106,10 @@ def best_match_for_path(self, path, raise404=False): # We flush the cache entry on page saving, so the cache should always # be up to date. - if settings.FEINCMS_USE_CACHE: - ck = path_to_cache_key(path) - page = django_cache.get(ck) - if page: - return page + ck = path_to_cache_key(path) + page = django_cache.get(ck) + if page: + return page if path: tokens = path.split('/') @@ -119,8 +118,7 @@ def best_match_for_path(self, path, raise404=False): try: page = self.active().filter(_cached_url__in=paths).extra( select={'_url_length': 'LENGTH(_cached_url)'}).order_by('-_url_length')[0] - if settings.FEINCMS_USE_CACHE: - django_cache.set(ck, page) + django_cache.set(ck, page) return page except IndexError: if raise404: @@ -331,9 +329,8 @@ def save(self, *args, **kwargs): super(Page, self).save(*args, **kwargs) # Okay, we changed the URL -- remove the old stale entry from the cache - if settings.FEINCMS_USE_CACHE: - ck = path_to_cache_key( self._original_cached_url.strip('/') ) - django_cache.delete(ck) + ck = path_to_cache_key( self._original_cached_url.strip('/') ) + django_cache.delete(ck) # If our cached URL changed we need to update all descendants to # reflect the changes. Since this is a very expensive operation diff --git a/tests/tests.py b/tests/tests.py index 416868d4f..5494f7076 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -258,7 +258,6 @@ def setUp(self): ('sidebar', 'Sidebar', 'inherited'), ), }) - feincms_settings.FEINCMS_USE_CACHE = True def login(self): self.assertTrue(self.client.login(username='test', password='test')) From cf746eb6be588b08a78032c5b867df4bb25bc8ae Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Sat, 29 Oct 2011 16:35:37 +1100 Subject: [PATCH 0148/1590] Add blocks to init_tinymce.html --- .../admin/content/richtext/init_tinymce.html | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/feincms/templates/admin/content/richtext/init_tinymce.html b/feincms/templates/admin/content/richtext/init_tinymce.html index c9059bec2..93da29551 100644 --- a/feincms/templates/admin/content/richtext/init_tinymce.html +++ b/feincms/templates/admin/content/richtext/init_tinymce.html @@ -1,9 +1,12 @@ -{% if TINYMCE_JS_URL %} - -{% endif %} +{% block tinymce_script %} + {% if TINYMCE_JS_URL %} + + {% endif %} +{% endblock %} - + +{% endblock %} From 898f3645f94df1675c38e383ef45f76f632e735f Mon Sep 17 00:00:00 2001 From: Psyton Date: Sun, 30 Oct 2011 18:05:14 +0700 Subject: [PATCH 0149/1590] PIL 1.1.7 required integer --- feincms/templatetags/feincms_thumbnail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 81ce4f718..7452876fe 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -158,13 +158,13 @@ def cropscale(filename, size='200x200'): if dst_ratio < src_ratio: crop_height = src_height crop_width = crop_height * dst_ratio - x_offset = float(src_width - crop_width) / 2 + x_offset = int(float(src_width - crop_width) / 2) y_offset = 0 else: crop_width = src_width crop_height = crop_width / dst_ratio x_offset = 0 - y_offset = float(src_height - crop_height) / 2 + y_offset = int(float(src_height - crop_height) / 2) image = image.crop((x_offset, y_offset, x_offset+int(crop_width), y_offset+int(crop_height))) image = image.resize((dst_width, dst_height), Image.ANTIALIAS) From bd8ae47458ead0aced7028bb8cbffd1a6b0978de Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Sun, 6 Nov 2011 00:10:22 +0100 Subject: [PATCH 0150/1590] Remove unused imports --- feincms/admin/item_editor.py | 1 - feincms/admin/tree_editor.py | 2 -- feincms/content/section/models.py | 3 +-- feincms/content/template/models.py | 4 ---- feincms/contrib/tagging.py | 2 +- feincms/default_settings.py | 1 - feincms/models.py | 3 +-- feincms/module/blog/models.py | 2 -- feincms/module/extensions/ct_tracker.py | 1 - feincms/module/medialibrary/models.py | 4 ---- feincms/module/page/models.py | 7 ++----- feincms/templatetags/feincms_tags.py | 1 - feincms/templatetags/feincms_thumbnail.py | 6 ++++-- feincms/views/cbv/urls.py | 2 +- feincms/views/legacy/urls.py | 2 +- 15 files changed, 11 insertions(+), 30 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index c13e48a13..e38a7f987 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -7,7 +7,6 @@ from django import forms, template from django.contrib import admin -from django.core.exceptions import ImproperlyConfigured from django.db.models import loading from django.forms.models import modelform_factory from django.http import Http404 diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 455029cc7..8fc3a295b 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -1,8 +1,6 @@ -from django.conf import settings as django_settings from django.contrib import admin from django.contrib.admin.views import main from django.db.models import Q -from django.db.models.query import QuerySet from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, HttpResponseServerError from django.utils import simplejson from django.utils.safestring import mark_safe diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 84c81f1b0..bc4ce7c04 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -1,10 +1,9 @@ from django import forms from django.conf import settings as django_settings from django.contrib.admin.widgets import AdminRadioSelect -from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.core.exceptions import ImproperlyConfigured from django.db import models from django.template.loader import render_to_string -from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from feincms import settings diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index be58454bb..aa918291e 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -1,14 +1,10 @@ import os -from django import forms -from django.conf import settings from django.db import models from django.template.loader import (Context, Template, TemplateDoesNotExist, find_template_loader) from django.utils.translation import ugettext_lazy as _ -from feincms.admin.item_editor import ItemEditorForm - DEFAULT_TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 0ddcc2028..13bd48b7d 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -50,7 +50,7 @@ def __init__(self, filter_horizontal=False, *args, **kwargs): self.filter_horizontal = filter_horizontal def formfield(self, **defaults): - from tagging.models import Tag, TaggedItem + from tagging.models import Tag from tagging.utils import parse_tag_input if self.filter_horizontal: diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 46215a2cc..6093ff216 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -11,7 +11,6 @@ from os.path import join -import django from django.conf import settings # ------------------------------------------------------------------------ diff --git a/feincms/models.py b/feincms/models.py index 8e92b02f0..77d8db783 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -5,7 +5,6 @@ the feincms\_ namespace. """ -import itertools import operator import warnings @@ -21,7 +20,7 @@ from django.utils.encoding import force_unicode from django.utils.translation import ugettext_lazy as _ -from feincms import settings, ensure_completely_loaded +from feincms import ensure_completely_loaded from feincms.utils import get_object, copy_model_instance try: diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index 246d6a332..689374b53 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -7,7 +7,6 @@ from datetime import datetime -from django.contrib import admin from django.db import models from django.db.models import signals from django.utils.translation import ugettext_lazy as _ @@ -15,7 +14,6 @@ from feincms.admin import item_editor from feincms.management.checker import check_database_schema from feincms.models import Base -from feincms.utils import get_object class EntryManager(models.Manager): diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index dc165270f..f4d04e057 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -18,7 +18,6 @@ """ from django.contrib.contenttypes.models import ContentType -from django.db import models from django.db.models.signals import class_prepared, post_save, pre_save from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 545e55896..c68072603 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -15,15 +15,12 @@ from django import forms from django.contrib import admin, messages from django.contrib.auth.decorators import permission_required -from django.contrib.contenttypes.models import ContentType -from django.conf import settings as django_settings from django.db import models from django.http import HttpResponseRedirect from django.shortcuts import render_to_response from django.template.context import RequestContext from django.template.defaultfilters import filesizeformat, slugify from django.utils.safestring import mark_safe -from django.utils import translation from django.utils.translation import ungettext, ugettext_lazy as _ from django.views.decorators.csrf import csrf_protect @@ -417,7 +414,6 @@ def changelist_view(self, request, extra_context=None): @permission_required('medialibrary.add_mediafile') def bulk_upload(request): from django.core.urlresolvers import reverse - from django.utils.functional import lazy def import_zipfile(request, category_id, data): import zipfile diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 50ec4ac9b..11d11c55f 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -8,7 +8,6 @@ import md5 import re -import sys import warnings from django import forms @@ -26,7 +25,7 @@ from django.http import Http404, HttpResponseRedirect from django.utils.datastructures import SortedDict from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _, ugettext +from django.utils.translation import ugettext_lazy as _ from django.db.transaction import commit_on_success from mptt.models import MPTTModel @@ -34,11 +33,9 @@ from feincms import settings, ensure_completely_loaded from feincms.admin import item_editor, tree_editor from feincms.management.checker import check_database_schema -from feincms.models import Base, create_base_model +from feincms.models import create_base_model from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin -import feincms.admin.filterspecs - # ------------------------------------------------------------------------ def path_to_cache_key(path): diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 3f949d173..acd112f81 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -1,6 +1,5 @@ from django import template from django.template.loader import render_to_string -from feincms import settings as feincms_settings from feincms import utils diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index c1e22e992..b11a1a6dc 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -1,4 +1,7 @@ -import os +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + import re from cStringIO import StringIO # Try to import PIL in either of the two ways it can end up installed. @@ -14,7 +17,6 @@ raise Exception, 'FeinCMS requires PIL to be installed' from django import template -from django.conf import settings from django.utils.encoding import force_unicode from django.core.files.storage import default_storage from django.core.files.base import ContentFile diff --git a/feincms/views/cbv/urls.py b/feincms/views/cbv/urls.py index 8024afe14..f4a21e70e 100644 --- a/feincms/views/cbv/urls.py +++ b/feincms/views/cbv/urls.py @@ -1,7 +1,7 @@ from __future__ import absolute_import -from django.conf.urls.defaults import patterns, include, url +from django.conf.urls.defaults import patterns, url from .views import Handler handler = Handler.as_view() diff --git a/feincms/views/legacy/urls.py b/feincms/views/legacy/urls.py index 09e607151..128ae3be6 100644 --- a/feincms/views/legacy/urls.py +++ b/feincms/views/legacy/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, include, url +from django.conf.urls.defaults import patterns, url from feincms.views.legacy.views import handler From b4126456f792eb0144ee48b83fecb1161f1a8682 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Sun, 6 Nov 2011 00:11:26 +0100 Subject: [PATCH 0151/1590] Remove unused code --- feincms/admin/tree_editor.py | 6 ++---- feincms/contrib/tagging.py | 2 +- feincms/management/commands/feincms_validate.py | 1 - feincms/management/commands/rebuild_mptt.py | 1 - feincms/models.py | 2 +- feincms/module/medialibrary/models.py | 2 +- feincms/views/cbv/views.py | 1 - 7 files changed, 5 insertions(+), 10 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 8fc3a295b..2d08d8341 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -141,8 +141,6 @@ def get_results(self, request): super(ChangeList, self).get_results(request) - opts = self.model_admin.opts - label = opts.app_label + '.' + opts.get_change_permission() for item in self.result_list: if settings.FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS: item.feincms_editable = self.model_admin.has_change_permission(request, item) @@ -232,7 +230,7 @@ def _collect_editable_booleans(self): # to the ModelAdmin class try: item = getattr(self.__class__, field) - except (AttributeError, TypeError), e: + except (AttributeError, TypeError): continue attr = getattr(item, 'editable_boolean_field', None) @@ -294,7 +292,7 @@ def _toggle_boolean(self, request): # Construct html snippets to send back to client for status update data = self._ajax_editable_booleans[attr](self, obj) - except Exception, e: + except Exception: logging.exception("Unhandled exception while toggling %s on %s", attr, obj) return HttpResponseServerError("Unable to toggle %s on %s" % (attr, obj)) diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 13bd48b7d..8052f0a39 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -42,7 +42,7 @@ class MyModel(models.Model): class TagSelectFormField(forms.MultipleChoiceField): def clean(self, value): - return taglist_to_string(list(value)); + return taglist_to_string(list(value)) class TagSelectField(TagField): def __init__(self, filter_horizontal=False, *args, **kwargs): diff --git a/feincms/management/commands/feincms_validate.py b/feincms/management/commands/feincms_validate.py index 4eaefe7e9..3c003b47c 100644 --- a/feincms/management/commands/feincms_validate.py +++ b/feincms/management/commands/feincms_validate.py @@ -1,6 +1,5 @@ # ------------------------------------------------------------------------ # coding=utf-8 -# $Id$ # ------------------------------------------------------------------------ """ ``feincms_validate`` diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index 373fe456d..3bebb9454 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -1,6 +1,5 @@ # ------------------------------------------------------------------------ # coding=utf-8 -# $Id$ # ------------------------------------------------------------------------ """ ``rebuild_mptt`` diff --git a/feincms/models.py b/feincms/models.py index 77d8db783..f270031a9 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -316,7 +316,7 @@ def register_extensions(cls, *extensions): fn = get_object('%s.%s.register' % (path, ext)) if fn: break - except ImportError, e: + except ImportError: pass if not fn: diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index c68072603..8ef2917f8 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -158,7 +158,7 @@ def __unicode__(self): trans = self.translation except models.ObjectDoesNotExist: pass - except AttributeError, e: + except AttributeError: pass if trans: diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 54455a37e..b0a2b3417 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -107,7 +107,6 @@ def handler(self, request, *args, **kwargs): except Http404, e: if settings.FEINCMS_CMS_404_PAGE: try: - http404 = e request.original_path_info = request.path_info request.path_info = settings.FEINCMS_CMS_404_PAGE response = super(Handler, self).handler(request, *args, **kwargs) From 6859b56891ab132aa0b10d9f24a61e462e74681c Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Sun, 6 Nov 2011 00:12:00 +0100 Subject: [PATCH 0152/1590] PEPify some white space --- feincms/admin/item_editor.py | 6 +++--- feincms/content/medialibrary/models.py | 1 - feincms/content/medialibrary/v2.py | 2 -- feincms/content/raw/models.py | 1 - feincms/contrib/fields.py | 2 +- feincms/contrib/tagging.py | 1 + feincms/management/commands/update_rsscontent.py | 1 - feincms/module/medialibrary/models.py | 1 - feincms/utils/templatetags.py | 1 - feincms/views/cbv/views.py | 3 +-- feincms/views/generic/create_update.py | 1 - feincms/views/generic/date_based.py | 1 - feincms/views/generic/list_detail.py | 1 - feincms/views/generic/simple.py | 1 - 14 files changed, 6 insertions(+), 17 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index e38a7f987..69bab16de 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -66,13 +66,13 @@ def __init__(self, model, admin_site): # This works in Django 1.3 and lower # In Django 1.4 inline instances are generated using overridden get_inline_instances() self.append_feincms_inlines(self.inline_instances) - + def get_inline_instances(self, request): inline_instances = super(ItemEditor, self).get_inline_instances(request) self.append_feincms_inlines(inline_instances) - + return inline_instances - + def append_feincms_inlines(self, inline_instances): """ Append generated FeinCMS content inlines to native django inlines. """ for inline_class in self.get_feincms_inlines(self.model): diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 0b5c13f20..6913a36e6 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -124,7 +124,6 @@ def render(self, **kwargs): 'content/mediafile/default.html', ], { 'content': self, 'request': request }) - @classmethod def default_create_content_type(cls, cms_model): return cms_model.create_content_type(cls, POSITION_CHOICES=( diff --git a/feincms/content/medialibrary/v2.py b/feincms/content/medialibrary/v2.py index 901e3a75f..3d1ce4b6a 100644 --- a/feincms/content/medialibrary/v2.py +++ b/feincms/content/medialibrary/v2.py @@ -59,5 +59,3 @@ def render(self, **kwargs): 'content/mediafile/%s.html' % self.type, 'content/mediafile/default.html', ], ctx) - - diff --git a/feincms/content/raw/models.py b/feincms/content/raw/models.py index 213e2bb6d..827d08247 100644 --- a/feincms/content/raw/models.py +++ b/feincms/content/raw/models.py @@ -20,4 +20,3 @@ class Meta: def render(self, **kwargs): return mark_safe(self.text) - diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 847653dc6..04e8edadc 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -82,4 +82,4 @@ def _flatten_value(self, value): add_introspection_rules(rules=[JSONField_introspection_rule], patterns=["^feincms\.contrib\.fields"]) except ImportError: - pass \ No newline at end of file + pass diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 8052f0a39..6994ba320 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -57,6 +57,7 @@ def formfield(self, **defaults): widget = FilteredSelectMultiple(self.verbose_name, is_stacked=False) else: widget = forms.SelectMultiple() + def _render(name, value, attrs=None, *args, **kwargs): value = parse_tag_input(value) return type(widget).render(widget, name, value, attrs, *args, **kwargs) diff --git a/feincms/management/commands/update_rsscontent.py b/feincms/management/commands/update_rsscontent.py index 35f209876..ee4994a18 100644 --- a/feincms/management/commands/update_rsscontent.py +++ b/feincms/management/commands/update_rsscontent.py @@ -22,4 +22,3 @@ def handle(self, date_format='', *args, **options): content.cache_content(date_format=date_format) else: content.cache_content() - diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 8ef2917f8..961ce13df 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -472,4 +472,3 @@ def save_model(self, request, obj, form, change): #------------------------------------------------------------------------- - diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index 2e4a849f9..d9c4af9cf 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -169,4 +169,3 @@ def render(self, context): context[self.var_name] = self.what(instance, _parse_args(self.args, context)) return '' - diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index b0a2b3417..e2a99f3b2 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -14,6 +14,7 @@ class HandlerBase(TemplateView): def get(self, request, *args, **kwargs): return self.handler(request, *args, **kwargs) + def post(self, request, *args, **kwargs): return self.handler(request, *args, **kwargs) @@ -118,5 +119,3 @@ def handler(self, request, *args, **kwargs): raise # ------------------------------------------------------------------------ - - diff --git a/feincms/views/generic/create_update.py b/feincms/views/generic/create_update.py index 8ffe4c75f..be8d7ccf9 100644 --- a/feincms/views/generic/create_update.py +++ b/feincms/views/generic/create_update.py @@ -5,4 +5,3 @@ create_object = add_page_to_extra_context(create_update.create_object) update_object = add_page_to_extra_context(create_update.update_object) delete_object = add_page_to_extra_context(create_update.delete_object) - diff --git a/feincms/views/generic/date_based.py b/feincms/views/generic/date_based.py index 1b0474ad8..a4b9df290 100644 --- a/feincms/views/generic/date_based.py +++ b/feincms/views/generic/date_based.py @@ -9,4 +9,3 @@ archive_day = add_page_to_extra_context(date_based.archive_day) archive_today = add_page_to_extra_context(date_based.archive_today) object_detail = add_page_to_extra_context(date_based.object_detail) - diff --git a/feincms/views/generic/list_detail.py b/feincms/views/generic/list_detail.py index 6684e5abe..c570d6c84 100644 --- a/feincms/views/generic/list_detail.py +++ b/feincms/views/generic/list_detail.py @@ -4,4 +4,3 @@ object_list = add_page_to_extra_context(list_detail.object_list) object_detail = add_page_to_extra_context(list_detail.object_detail) - diff --git a/feincms/views/generic/simple.py b/feincms/views/generic/simple.py index 22f1b7eaa..71efcca1c 100644 --- a/feincms/views/generic/simple.py +++ b/feincms/views/generic/simple.py @@ -3,4 +3,3 @@ direct_to_template = add_page_to_extra_context(simple.direct_to_template) - From 0f6b29126de905a995d33d008b34ba0d6c87b95c Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 7 Nov 2011 13:01:55 +0100 Subject: [PATCH 0153/1590] Appease js lint --- feincms/static/feincms/frontend_editing.js | 4 ++-- feincms/static/feincms/ie_compat.js | 4 ++-- feincms/static/feincms/item_editor.js | 14 +++++++------- feincms/static/feincms/toolbox.js | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/feincms/static/feincms/frontend_editing.js b/feincms/static/feincms/frontend_editing.js index e1a132c6d..08dd3d5c5 100644 --- a/feincms/static/feincms/frontend_editing.js +++ b/feincms/static/feincms/frontend_editing.js @@ -29,12 +29,12 @@ fe_tools.hide(); } ); - } + }; feincms.fe_update_content = function(identifier, content) { var region = $('#' + identifier); region.animate({'opacity': 0}).html(content); region.animate({'opacity': 1.5}).animate({'opacity': 0.6}); feincms.fe_init_animations(); - } + }; })(feincms.jQuery); diff --git a/feincms/static/feincms/ie_compat.js b/feincms/static/feincms/ie_compat.js index 7cd1ec39f..25a245a64 100644 --- a/feincms/static/feincms/ie_compat.js +++ b/feincms/static/feincms/ie_compat.js @@ -12,7 +12,7 @@ if(typeof(Array.prototype.indexOf) == 'undefined') { else j=this.indexOf(elm,j+i); return j!==this.length?j:-1; - } + }; } if (!Array.prototype.filter) @@ -23,7 +23,7 @@ if (!Array.prototype.filter) if (typeof fun != "function") throw new TypeError(); - var res = new Array(); + var res = []; var thisp = arguments[1]; for (var i = 0; i < len; i++) { diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index a6756da12..94e67fe26 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -6,7 +6,7 @@ if(!Array.indexOf) { } } return -1; - } + }; } (function($){ @@ -174,7 +174,7 @@ if(!Array.indexOf) { } function create_new_spare_form(modvar) { - var old_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val()); + var old_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val(), 10); // **** UGLY CODE WARNING, avert your gaze! **** // for some unknown reason, the add-button click handler function // fails on the first triggerHandler call in some rare cases; @@ -186,7 +186,7 @@ if(!Array.indexOf) { 'div.add-row > a').triggerHandler('click'); if(returned==false) break; // correct return value } - var new_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val()); + var new_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val(), 10); if(new_form_count > old_form_count){ return $('#'+modvar+'_set-'+(new_form_count-1)); } @@ -239,10 +239,10 @@ if(!Array.indexOf) { } function sort_by_ordering(e1, e2) { - var v1 = parseInt($('.order-field', e1).val()) || 0; - var v2 = parseInt($('.order-field', e2).val()) || 0; + var v1 = parseInt($('.order-field', e1).val(), 10) || 0; + var v2 = parseInt($('.order-field', e2).val(), 10) || 0; return v1 > v2 ? 1 : -1; - }; + } function give_ordering_to_content_types() { for (var i=0; i 327 */ -var extract_item_id = function(elem_id) { +function extract_item_id(elem_id) { var i = elem_id.indexOf('-'); if(i >= 0) - return parseInt(elem_id.slice(i+1)); + return parseInt(elem_id.slice(i+1), 10); return 0; } @@ -19,13 +19,13 @@ var extract_item_id = function(elem_id) { replace_element(0, '
New Stuff!
') */ -var replace_element = function(i, html) { +function replace_element(i, html) { var r_id = $(html).attr('id'); $('#' + r_id).replaceWith(html); } /* Same as above, but processes an array of html snippets */ -var replace_elements = function(data) { +function replace_elements(data) { $.each(data, replace_element); } @@ -36,7 +36,7 @@ $.ajaxSetup({ beforeSend: function(xhr, settings) { function getCookie(name) { var cookieValue = null; - if (document.cookie && document.cookie != '') { + if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); @@ -57,7 +57,7 @@ $.ajaxSetup({ }); /* OnClick handler to toggle a boolean field via AJAX */ -var inplace_toggle_boolean = function(item_id, attr) { +function inplace_toggle_boolean(item_id, attr) { $.ajax({ url: ".", type: "POST", From 77991fc5d5a0e98c9050ad09c6dbe713b1498d81 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 7 Nov 2011 13:49:00 +0100 Subject: [PATCH 0154/1590] Clean up extension option layout in item editor admin --- feincms/contrib/tagging.py | 9 ++++++++- feincms/module/extensions/datepublisher.py | 9 +++++---- feincms/module/extensions/translations.py | 4 +++- feincms/module/page/models.py | 16 ++++++++++++---- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 6994ba320..05d81f710 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -10,9 +10,10 @@ from __future__ import absolute_import -from django.db.models.signals import pre_save from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple +from django.db.models.signals import pre_save +from django.utils.translation import ugettext_lazy as _ from tagging.fields import TagField @@ -106,6 +107,12 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_fi admin_cls.list_display.append(field_name) admin_cls.list_filter.append(field_name) + if hasattr(admin_cls, 'add_extension_options'): + admin_cls.add_extension_options(_('Tagging'), { + 'fields': (field_name,), + 'classes': ('collapse',), + }) + if sort_tags: pre_save.connect(pre_save_handler, sender=cls) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 9476cf78f..8d4654bf6 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -54,6 +54,7 @@ def register(cls, admin_cls): # Patch in rounding the pub and pub_end dates on save orig_save = cls.save + def granular_save(obj, *args, **kwargs): if obj.publication_date: obj.publication_date = granular_now(obj.publication_date) @@ -85,9 +86,9 @@ def datepublisher_admin(self, page): admin_cls.list_display.insert(pos + 1, 'datepublisher_admin') - admin_cls.fieldsets.append((_('Date-based publishing'), { - 'fields': ('publication_date', 'publication_end_date'), - 'classes': ('collapse',), - })) + admin_cls.add_extension_options(_('Date-based publishing'), { + 'fields': ('publication_date', 'publication_end_date'), + 'classes': ('collapse',), + }) # ------------------------------------------------------------------------ diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 3d5f3df19..f04f306e7 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -183,7 +183,9 @@ def available_translations_admin(self, page): available_translations_admin.short_description = _('translations') admin_cls.available_translations_admin = available_translations_admin - admin_cls.fieldsets[0][1]['fields'].extend(['language', 'translation_of']) + if hasattr(admin_cls, 'add_extension_options'): + admin_cls.add_extension_options('language', 'translation_of') + admin_cls.list_display.extend(['language', 'available_translations_admin']) admin_cls.list_filter.extend(['language']) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 11d11c55f..c1b411f15 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -669,20 +669,21 @@ class Media: # the fieldsets config here is used for the add_view, it has no effect # for the change_view which is completely customized anyway - unknown_fields = ['override_url', 'redirect_to'] + unknown_fields = ['template_key', 'parent', 'override_url', 'redirect_to'] + fieldset_insertion_index = 2 fieldsets = [ (None, { 'fields': [ ('title', 'slug'), - ('parent', 'active', 'in_navigation'), - 'template_key', + ('active', 'in_navigation'), ], }), - item_editor.FEINCMS_CONTENT_FIELDSET, (_('Other options'), { 'classes': ['collapse',], 'fields': unknown_fields, }), + # <-- insertion point, extensions appear here, see insertion_index above + item_editor.FEINCMS_CONTENT_FIELDSET, ] readonly_fields = [] list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] @@ -693,6 +694,13 @@ class Media: raw_id_fields = ['parent'] radio_fields = {'template_key': admin.HORIZONTAL} + @classmethod + def add_extension_options(cls, *f): + if isinstance(f[-1], dict): # called with a fieldset + cls.fieldsets.insert(cls.fieldset_insertion_index, f) + else: # assume called with "other" fields + cls.fieldsets[1][1]['fields'].extend(f) + def __init__(self, *args, **kwargs): ensure_completely_loaded() From 6568ce084572223cafdae03d6637be4ab2fafc18 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 7 Nov 2011 14:09:04 +0100 Subject: [PATCH 0155/1590] Automatically make extensions collapsible --- feincms/contrib/tagging.py | 3 +-- feincms/module/extensions/datepublisher.py | 1 - feincms/module/page/models.py | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 05d81f710..898fdafa5 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -109,8 +109,7 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_fi if hasattr(admin_cls, 'add_extension_options'): admin_cls.add_extension_options(_('Tagging'), { - 'fields': (field_name,), - 'classes': ('collapse',), + 'fields': (field_name,) }) if sort_tags: diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 8d4654bf6..d307eaebd 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -88,7 +88,6 @@ def datepublisher_admin(self, page): admin_cls.add_extension_options(_('Date-based publishing'), { 'fields': ('publication_date', 'publication_end_date'), - 'classes': ('collapse',), }) # ------------------------------------------------------------------------ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c1b411f15..e8ee05556 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -698,6 +698,8 @@ class Media: def add_extension_options(cls, *f): if isinstance(f[-1], dict): # called with a fieldset cls.fieldsets.insert(cls.fieldset_insertion_index, f) + f[1]['classes'] = list(f[1].get('classes', [])) + f[1]['classes'].append('collapse') else: # assume called with "other" fields cls.fieldsets[1][1]['fields'].extend(f) From 46599cf64fe9b37f8cf40c1b590326d8ab057d53 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 7 Nov 2011 14:39:06 +0100 Subject: [PATCH 0156/1590] Update jquery to 1.7 --- feincms/static/feincms/jquery-1.5.1.min.js | 16 - .../{jquery-1.5.1.js => jquery-1.7.js} | 5296 ++++++++++------- feincms/static/feincms/jquery-1.7.min.js | 4 + .../templates/admin/feincms/fe_editor.html | 2 +- .../admin/feincms/fe_editor_done.html | 2 +- feincms/templates/admin/feincms/fe_tools.html | 2 +- .../templates/admin/feincms/item_editor.html | 2 +- .../templates/admin/feincms/tree_editor.html | 2 +- 8 files changed, 3149 insertions(+), 2177 deletions(-) delete mode 100644 feincms/static/feincms/jquery-1.5.1.min.js rename feincms/static/feincms/{jquery-1.5.1.js => jquery-1.7.js} (58%) create mode 100644 feincms/static/feincms/jquery-1.7.min.js diff --git a/feincms/static/feincms/jquery-1.5.1.min.js b/feincms/static/feincms/jquery-1.5.1.min.js deleted file mode 100644 index 6437874c6..000000000 --- a/feincms/static/feincms/jquery-1.5.1.min.js +++ /dev/null @@ -1,16 +0,0 @@ -/*! - * jQuery JavaScript Library v1.5.1 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Wed Feb 23 13:55:29 2011 -0500 - */ -(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;ic)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function w(){return!0}function v(){return!1}function g(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return E.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g1){var f=E.call(arguments,0),g=b,h=function(a){return function(b){f[a]=arguments.length>1?E.call(arguments,0):b,--g||c.resolveWith(e,f)}};while(b--)a=f[b],a&&d.isFunction(a.promise)?a.promise().then(h(b),c.reject):--g;g||c.resolveWith(e,f)}else c!==a&&c.resolve(a);return e},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="
a";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e),b=e=f=null}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!g(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,h=b.nodeType,i=h?d.cache:b,j=h?b[d.expando]:d.expando;if(!i[j])return;if(c){var k=e?i[j][f]:i[j];if(k){delete k[c];if(!g(k))return}}if(e){delete i[j][f];if(!g(i[j]))return}var l=i[j][f];d.support.deleteExpando||i!=a?delete i[j]:i[j]=null,l?(i[j]={},h||(i[j].toJSON=d.noop),i[j][f]=l):h&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var k=i?f:0,l=i?f+1:h.length;k=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=k.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&l.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:m.test(a.nodeName)||n.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var p=/\.(.*)$/,q=/^(?:textarea|input|select)$/i,r=/\./g,s=/ /g,t=/[^\w\s.|`]/g,u=function(a){return a.replace(t,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=v;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),u).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(p,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(q.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return q.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return q.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(d||!l.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return k(c,null,null,[a]).length>0})}(),function(){var a=c.createElement("div");a.innerHTML="
";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(var g=c;g0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div
","
"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1>");try{for(var c=0,e=this.length;c1&&l0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){$(a,e),f=_(a),g=_(e);for(h=0;f[h];++h)$(f[h],g[h])}if(b){Z(a,e);if(c){f=_(a),g=_(e);for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]===""&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bb=/alpha\([^)]*\)/i,bc=/opacity=([^)]*)/,bd=/-([a-z])/ig,be=/([A-Z])/g,bf=/^-?\d+(?:px)?$/i,bg=/^-?\d/,bh={position:"absolute",visibility:"hidden",display:"block"},bi=["Left","Right"],bj=["Top","Bottom"],bk,bl,bm,bn=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bk(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bk)return bk(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bd,bn)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bo(a,b,e):d.swap(a,bh,function(){f=bo(a,b,e)});if(f<=0){f=bk(a,b,b),f==="0px"&&bm&&(f=bm(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bf.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bb.test(f)?f.replace(bb,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bl=function(a,c,e){var f,g,h;e=e.replace(be,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bm=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bf.test(d)&&bg.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bk=bl||bm,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bp=/%20/g,bq=/\[\]$/,br=/\r?\n/g,bs=/#.*$/,bt=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bu=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bv=/(?:^file|^widget|\-extension):$/,bw=/^(?:GET|HEAD)$/,bx=/^\/\//,by=/\?/,bz=/)<[^<]*)*<\/script>/gi,bA=/^(?:select|textarea)/i,bB=/\s+/,bC=/([?&])_=[^&]*/,bD=/(^|\-)([a-z])/g,bE=function(a,b,c){return b+c.toUpperCase()},bF=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,bG=d.fn.load,bH={},bI={},bJ,bK;try{bJ=c.location.href}catch(bL){bJ=c.createElement("a"),bJ.href="",bJ=bJ.href}bK=bF.exec(bJ.toLowerCase()),d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bG)return bG.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("
").append(c.replace(bz,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bA.test(this.nodeName)||bu.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(br,"\r\n")}}):{name:b.name,value:c.replace(br,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bJ,isLocal:bv.test(bK[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bM(bH),ajaxTransport:bM(bI),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bP(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bQ(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bD,bE)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bt.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bs,"").replace(bx,bK[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bB),e.crossDomain||(q=bF.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bK[1]||q[2]!=bK[2]||(q[3]||(q[1]==="http:"?80:443))!=(bK[3]||(bK[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bN(bH,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!bw.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(by.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bC,"$1_="+w);e.url=x+(x===e.url?(by.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bN(bI,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bO(g,a[g],c,f);return e.join("&").replace(bp,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bR=d.now(),bS=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bR++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bS.test(b.url)||f&&bS.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bS,l),b.url===j&&(f&&(k=k.replace(bS,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bT=d.now(),bU,bV;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bX()||bY()}:bX,bV=d.ajaxSettings.xhr(),d.support.ajax=!!bV,d.support.cors=bV&&"withCredentials"in bV,bV=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),(!a.crossDomain||a.hasContent)&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bU[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bU||(bU={},bW()),h=bT++,g.onreadystatechange=bU[h]=c):c()},abort:function(){c&&c(0,1)}}}});var bZ={},b$=/^(?:toggle|show|hide)$/,b_=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,ca,cb=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(cc("show",3),a,b,c);for(var g=0,h=this.length;g=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:cc("show",1),slideUp:cc("hide",1),slideToggle:cc("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!ca&&(ca=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b
";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=cf.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!cf.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=cg(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=cg(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-1.5.1.js b/feincms/static/feincms/jquery-1.7.js similarity index 58% rename from feincms/static/feincms/jquery-1.5.1.js rename to feincms/static/feincms/jquery-1.7.js index 78fcfa469..eda55db35 100644 --- a/feincms/static/feincms/jquery-1.5.1.js +++ b/feincms/static/feincms/jquery-1.7.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v1.5.1 + * jQuery JavaScript Library v1.7 * http://jquery.com/ * * Copyright 2011, John Resig @@ -11,12 +11,14 @@ * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * - * Date: Wed Feb 23 13:55:29 2011 -0500 + * Date: Thu Nov 3 16:18:21 2011 -0400 */ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) -var document = window.document; +var document = window.document, + navigator = window.navigator, + location = window.location; var jQuery = (function() { // Define a local copy of jQuery @@ -35,8 +37,8 @@ var jQuery = function( selector, context ) { rootjQuery, // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/, + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, @@ -63,21 +65,24 @@ var jQuery = function( selector, context ) { rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, - // Has the ready events already been bound? - readyBound = false, - // The deferred used on DOM ready readyList, - // Promise methods - promiseMethods = "then done fail isResolved isRejected promise".split( " " ), - // The ready event handler DOMContentLoaded, @@ -113,7 +118,7 @@ jQuery.fn = jQuery.prototype = { if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; - this.selector = "body"; + this.selector = selector; this.length = 1; return this; } @@ -121,7 +126,13 @@ jQuery.fn = jQuery.prototype = { // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? - match = quickExpr.exec( selector ); + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { @@ -129,7 +140,7 @@ jQuery.fn = jQuery.prototype = { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; - doc = (context ? context.ownerDocument || context : document); + doc = ( context ? context.ownerDocument || context : document ); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest @@ -146,7 +157,7 @@ jQuery.fn = jQuery.prototype = { } else { ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; } return jQuery.merge( this, selector ); @@ -176,7 +187,7 @@ jQuery.fn = jQuery.prototype = { // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { - return (context || rootjQuery).find( selector ); + return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) @@ -190,7 +201,7 @@ jQuery.fn = jQuery.prototype = { return rootjQuery.ready( selector ); } - if (selector.selector !== undefined) { + if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } @@ -202,7 +213,7 @@ jQuery.fn = jQuery.prototype = { selector: "", // The current version of jQuery being used - jquery: "1.5.1", + jquery: "1.7", // The default length of a jQuery object is 0 length: 0, @@ -247,7 +258,7 @@ jQuery.fn = jQuery.prototype = { ret.context = this.context; if ( name === "find" ) { - ret.selector = this.selector + (this.selector ? " " : "") + selector; + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } @@ -268,7 +279,7 @@ jQuery.fn = jQuery.prototype = { jQuery.bindReady(); // Add the callback - readyList.done( fn ); + readyList.add( fn ); return this; }, @@ -378,9 +389,11 @@ jQuery.extend = jQuery.fn.extend = function() { jQuery.extend({ noConflict: function( deep ) { - window.$ = _$; + if ( window.$ === jQuery ) { + window.$ = _$; + } - if ( deep ) { + if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } @@ -394,15 +407,19 @@ jQuery.extend({ // the ready event fires. See #6781 readyWait: 1, - // Handle when the DOM is ready - ready: function( wait ) { - // A third-party is pushing the ready event forwards - if ( wait === true ) { - jQuery.readyWait--; + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); } + }, - // Make sure that the DOM is not already loaded - if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); @@ -417,7 +434,7 @@ jQuery.extend({ } // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); + readyList.fireWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.trigger ) { @@ -427,11 +444,11 @@ jQuery.extend({ }, bindReady: function() { - if ( readyBound ) { + if ( readyList ) { return; } - readyBound = true; + readyList = jQuery.Callbacks( "once memory" ); // Catch cases where $(document).ready() is called after the // browser event has already occurred. @@ -452,7 +469,7 @@ jQuery.extend({ } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes - document.attachEvent("onreadystatechange", DOMContentLoaded); + document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); @@ -487,8 +504,8 @@ jQuery.extend({ return obj && typeof obj === "object" && "setInterval" in obj; }, - isNaN: function( obj ) { - return obj == null || !rdigit.test( obj ) || isNaN( obj ); + isNumeric: function( obj ) { + return obj != null && rdigit.test( obj ) && !isNaN( obj ); }, type: function( obj ) { @@ -505,10 +522,15 @@ jQuery.extend({ return false; } - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 return false; } @@ -540,67 +562,66 @@ jQuery.extend({ // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test(data.replace(rvalidescape, "@") - .replace(rvalidtokens, "]") - .replace(rvalidbraces, "")) ) { + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { - // Try to use the native JSON parser first - return window.JSON && window.JSON.parse ? - window.JSON.parse( data ) : - (new Function("return " + data))(); + return ( new Function( "return " + data ) )(); - } else { - jQuery.error( "Invalid JSON: " + data ); } + jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing - // (xml & tmp used internally) - parseXML: function( data , xml , tmp ) { - - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - - tmp = xml.documentElement; - - if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + parseXML: function( data ) { + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } - return xml; }, noop: function() {}, - // Evalulates a script in a global context + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { - if ( data && rnotwhite.test(data) ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, - script = document.createElement( "script" ); - - if ( jQuery.support.scriptEval() ) { - script.appendChild( document.createTextNode( data ) ); - } else { - script.text = data; - } - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); } }, + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, @@ -609,7 +630,7 @@ jQuery.extend({ each: function( object, callback, args ) { var name, i = 0, length = object.length, - isObj = length === undefined || jQuery.isFunction(object); + isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { @@ -635,8 +656,11 @@ jQuery.extend({ } } } else { - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } } } @@ -667,7 +691,7 @@ jQuery.extend({ // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type(array); + var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); @@ -679,14 +703,22 @@ jQuery.extend({ return ret; }, - inArray: function( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } } } @@ -731,15 +763,30 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var ret = [], value; + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their - // new value (or values). - for ( var i = 0, length = elems.length; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); - if ( value != null ) { - ret[ ret.length ] = value; + if ( value != null ) { + ret[ ret.length ] = value; + } } } @@ -750,36 +797,35 @@ jQuery.extend({ // A global GUID counter for objects guid: 1, - proxy: function( fn, proxy, thisObject ) { - if ( arguments.length === 2 ) { - if ( typeof proxy === "string" ) { - thisObject = fn; - fn = thisObject[ proxy ]; - proxy = undefined; + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } - } else if ( proxy && !jQuery.isFunction( proxy ) ) { - thisObject = proxy; - proxy = undefined; - } + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; } - if ( !proxy && fn ) { + // Simulated bind + var args = slice.call( arguments, 2 ), proxy = function() { - return fn.apply( thisObject || this, arguments ); + return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; - } // Set the guid of unique handler to the same of original handler, so it can be removed - if ( fn ) { - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - } + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - // So proxy can be declared as an argument return proxy; }, // Mutifunctional method to get and set values to a collection - // The value/s can be optionally by executed if its a function + // The value/s can optionally be executed if it's a function access: function( elems, key, value, exec, fn, pass ) { var length = elems.length; @@ -808,172 +854,7 @@ jQuery.extend({ }, now: function() { - return (new Date()).getTime(); - }, - - // Create a simple deferred (one callbacks list) - _Deferred: function() { - var // callbacks list - callbacks = [], - // stored [ context , args ] - fired, - // to avoid firing when already doing so - firing, - // flag to know if the deferred has been cancelled - cancelled, - // the deferred itself - deferred = { - - // done( f1, f2, ...) - done: function() { - if ( !cancelled ) { - var args = arguments, - i, - length, - elem, - type, - _fired; - if ( fired ) { - _fired = fired; - fired = 0; - } - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - deferred.done.apply( deferred, elem ); - } else if ( type === "function" ) { - callbacks.push( elem ); - } - } - if ( _fired ) { - deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); - } - } - return this; - }, - - // resolve with given context and args - resolveWith: function( context, args ) { - if ( !cancelled && !fired && !firing ) { - firing = 1; - try { - while( callbacks[ 0 ] ) { - callbacks.shift().apply( context, args ); - } - } - // We have to add a catch block for - // IE prior to 8 or else the finally - // block will never get executed - catch (e) { - throw e; - } - finally { - fired = [ context, args ]; - firing = 0; - } - } - return this; - }, - - // resolve with this as context and given arguments - resolve: function() { - deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments ); - return this; - }, - - // Has this deferred been resolved? - isResolved: function() { - return !!( firing || fired ); - }, - - // Cancel - cancel: function() { - cancelled = 1; - callbacks = []; - return this; - } - }; - - return deferred; - }, - - // Full fledged deferred (two callbacks list) - Deferred: function( func ) { - var deferred = jQuery._Deferred(), - failDeferred = jQuery._Deferred(), - promise; - // Add errorDeferred methods, then and promise - jQuery.extend( deferred, { - then: function( doneCallbacks, failCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ); - return this; - }, - fail: failDeferred.done, - rejectWith: failDeferred.resolveWith, - reject: failDeferred.resolve, - isRejected: failDeferred.isResolved, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - if ( promise ) { - return promise; - } - promise = obj = {}; - } - var i = promiseMethods.length; - while( i-- ) { - obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; - } - return obj; - } - } ); - // Make sure only one callback list will be used - deferred.done( failDeferred.cancel ).fail( deferred.cancel ); - // Unexpose cancel - delete deferred.cancel; - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - return deferred; - }, - - // Deferred helper - when: function( object ) { - var lastIndex = arguments.length, - deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ? - object : - jQuery.Deferred(), - promise = deferred.promise(); - - if ( lastIndex > 1 ) { - var array = slice.call( arguments, 0 ), - count = lastIndex, - iCallback = function( index ) { - return function( value ) { - array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value; - if ( !( --count ) ) { - deferred.resolveWith( promise, array ); - } - }; - }; - while( ( lastIndex-- ) ) { - object = array[ lastIndex ]; - if ( object && jQuery.isFunction( object.promise ) ) { - object.promise().then( iCallback(lastIndex), deferred.reject ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( promise, array ); - } - } else if ( deferred !== object ) { - deferred.resolve( object ); - } - return promise; + return ( new Date() ).getTime(); }, // Use of jQuery.browser is frowned upon. @@ -991,32 +872,29 @@ jQuery.extend({ }, sub: function() { - function jQuerySubclass( selector, context ) { - return new jQuerySubclass.fn.init( selector, context ); + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); } - jQuery.extend( true, jQuerySubclass, this ); - jQuerySubclass.superclass = this; - jQuerySubclass.fn = jQuerySubclass.prototype = this(); - jQuerySubclass.fn.constructor = jQuerySubclass; - jQuerySubclass.subclass = this.subclass; - jQuerySubclass.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { - context = jQuerySubclass(context); + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); } - return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; - jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; - var rootjQuerySubclass = jQuerySubclass(document); - return jQuerySubclass; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; }, browser: {} }); -// Create readyList deferred -readyList = jQuery._Deferred(); - // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); @@ -1033,12 +911,6 @@ if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } -if ( indexOf ) { - jQuery.inArray = function( elem, array ) { - return indexOf.call( array, elem ); - }; -} - // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; @@ -1084,238 +956,722 @@ function doScrollCheck() { jQuery.ready(); } -// Expose jQuery to the global object +// Expose jQuery as an AMD module, but only for AMD loaders that +// understand the issues with loading multiple versions of jQuery +// in a page that all might call define(). The loader will indicate +// they have special allowances for multiple jQuery versions by +// specifying define.amd.jQuery = true. Register as a named module, +// since jQuery can be concatenated with other files that may use define, +// but not use a proper concatenation script that understands anonymous +// AMD modules. A named AMD is safest and most robust way to register. +// Lowercase jquery is used because AMD module names are derived from +// file names, and jQuery is normally delivered in a lowercase file name. +if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); +} + return jQuery; })(); -(function() { +// String to Object flags format cache +var flagsCache = {}; - jQuery.support = {}; +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} - var div = document.createElement("div"); +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!memory; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ - div.style.display = "none"; - div.innerHTML = "
a"; + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); - var all = div.getElementsByTagName("*"), - a = div.getElementsByTagName("a")[0], - select = document.createElement("select"), - opt = select.appendChild( document.createElement("option") ), - input = div.getElementsByTagName("input")[0]; + + + +jQuery.support = (function() { + + var div = document.createElement( "div" ), + documentElement = document.documentElement, + all, + a, + select, + opt, + input, + marginDiv, + support, + fragment, + body, + testElementParent, + testElement, + testElementStyle, + tds, + events, + eventName, + i, + isSupported; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
a"; + + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { - return; + return {}; } - jQuery.support = { + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, + leadingWhitespace: ( div.firstChild.nodeType === 3 ), // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, + tbody: !div.getElementsByTagName( "tbody" ).length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, + htmlSerialize: !!div.getElementsByTagName( "link" ).length, // Get the style information from getAttribute - // (IE uses .cssText insted) - style: /red/.test( a.getAttribute("style") ), + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55$/.test( a.style.opacity ), + opacity: /^0.55/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) cssFloat: !!a.style.cssFloat, + // Make sure unknown elements (like HTML5 elems) are handled appropriately + unknownElems: !!div.getElementsByTagName( "nav" ).length, + // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) - checkOn: input.value === "on", + checkOn: ( input.value === "on" ), // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, deleteExpando: true, - optDisabled: false, - checkClone: false, noCloneEvent: true, - noCloneChecked: true, - boxModel: null, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, - reliableHiddenOffsets: true + reliableMarginRight: true }; + // Make sure checked status is properly cloned input.checked = true; - jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as diabled) + // (WebKit marks them as disabled) select.disabled = true; - jQuery.support.optDisabled = !opt.disabled; - - var _scriptEval = null; - jQuery.support.scriptEval = function() { - if ( _scriptEval === null ) { - var root = document.documentElement, - script = document.createElement("script"), - id = "script" + jQuery.now(); - - try { - script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); - } catch(e) {} - - root.insertBefore( script, root.firstChild ); - - // Make sure that the execution of code works by injecting a script - // tag with appendChild/createTextNode - // (IE doesn't support this, fails, and uses .text instead) - if ( window[ id ] ) { - _scriptEval = true; - delete window[ id ]; - } else { - _scriptEval = false; - } - - root.removeChild( script ); - // release memory in IE - root = script = id = null; - } - - return _scriptEval; - }; + support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; - - } catch(e) { - jQuery.support.deleteExpando = false; + } catch( e ) { + support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent("onclick", function click() { + div.attachEvent( "onclick", function() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) - jQuery.support.noCloneEvent = false; - div.detachEvent("onclick", click); + support.noCloneEvent = false; }); - div.cloneNode(true).fireEvent("onclick"); + div.cloneNode( true ).fireEvent( "onclick" ); } - div = document.createElement("div"); - div.innerHTML = ""; + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; - var fragment = document.createDocumentFragment(); - fragment.appendChild( div.firstChild ); + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); // WebKit doesn't clone checked state correctly in fragments - jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; // Figure out if the W3C box model works as expected - // document.body must exist before we can do this - jQuery(function() { - var div = document.createElement("div"), - body = document.getElementsByTagName("body")[0]; + div.style.width = div.style.paddingLeft = "1px"; + + // We don't want to do body-related feature tests on frameset + // documents, which lack a body. So we use + // document.getElementsByTagName("body")[0], which is undefined in + // frameset documents, while document.body isn’t. (7398) + body = document.getElementsByTagName("body")[ 0 ]; + // We use our own, invisible, body unless the body is already present + // in which case we use a div (#9239) + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + jQuery.extend( testElementStyle, { + position: "absolute", + left: "-999px", + top: "-999px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.innerHTML = "
t
"; + tds = div.getElementsByTagName( "td" ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } - // Frameset documents with no body should not run this code + // Run fixed position tests at doc ready to avoid a crash + // related to the invisible body in IE8 + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + conMarginTop = 1, + ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;", + vb = "visibility:hidden;border:0;", + style = "style='" + ptlm + "border:5px solid #000;padding:0;'", + html = "
" + + "" + + "
"; + + // Reconstruct a container + body = document.getElementsByTagName("body")[0]; if ( !body ) { + // Return for frameset docs that don't have a body + // These tests cannot be done return; } - div.style.width = div.style.paddingLeft = "1px"; - body.appendChild( div ); - jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; - - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
"; - jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; - } - - div.innerHTML = "
t
"; - var tds = div.getElementsByTagName("td"); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; - - tds[0].style.display = ""; - tds[1].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; - div.innerHTML = ""; - - body.removeChild( div ).style.display = "none"; - div = tds = null; - }); + container = document.createElement("div"); + container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); - // Technique from Juriy Zaytsev - // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - var eventSupported = function( eventName ) { - var el = document.createElement("div"); - eventName = "on" + eventName; - - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( !el.attachEvent ) { - return true; - } + // Construct a test element + testElement = document.createElement("div"); + testElement.style.cssText = ptlm + vb; - var isSupported = (eventName in el); - if ( !isSupported ) { - el.setAttribute(eventName, "return;"); - isSupported = typeof el[eventName] === "function"; - } - el = null; + testElement.innerHTML = html; + container.appendChild( testElement ); + outer = testElement.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; - return isSupported; - }; + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; - jQuery.support.submitBubbles = eventSupported("submit"); - jQuery.support.changeBubbles = eventSupported("change"); + inner.style.position = "fixed"; + inner.style.top = "20px"; - // release memory in IE - div = all = a = null; + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + body.removeChild( container ); + testElement = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); + + // Null connected elements to avoid leaks in IE + testElement = fragment = select = opt = body = marginDiv = div = input = null; + + return support; })(); +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; -var rbrace = /^(?:\{.*\}|\[.*\])$/; + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, @@ -1338,7 +1694,6 @@ jQuery.extend({ hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); }, @@ -1347,7 +1702,9 @@ jQuery.extend({ return; } - var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary @@ -1359,11 +1716,12 @@ jQuery.extend({ // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando, + isEvents = name === "events"; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all - if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { return; } @@ -1380,9 +1738,8 @@ jQuery.extend({ if ( !cache[ id ] ) { cache[ id ] = {}; - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } @@ -1392,37 +1749,53 @@ jQuery.extend({ // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { - cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + cache[ id ] = jQuery.extend( cache[ id ], name ); } else { - cache[ id ] = jQuery.extend(cache[ id ], name); + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } - thisCache = cache[ id ]; + privateCache = thisCache = cache[ id ]; - // Internal jQuery data is stored in a separate object inside the object's data + // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined - // data - if ( pvt ) { - if ( !thisCache[ internalKey ] ) { - thisCache[ internalKey ] = {}; + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; } - thisCache = thisCache[ internalKey ]; + thisCache = thisCache.data; } if ( data !== undefined ) { - thisCache[ name ] = data; + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; } - // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should - // not attempt to inspect the internal events object using jQuery.data, as this - // internal data object is undocumented and subject to change. - if ( name === "events" && !thisCache[name] ) { - return thisCache[ internalKey ] && thisCache[ internalKey ].events; + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; } - return getByName ? thisCache[ name ] : thisCache; + return ret; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { @@ -1430,7 +1803,12 @@ jQuery.extend({ return; } - var internalKey = jQuery.expando, isNode = elem.nodeType, + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, @@ -1445,22 +1823,42 @@ jQuery.extend({ } if ( name ) { - var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + thisCache = pvt ? cache[ id ] : cache[ id ].data; if ( thisCache ) { - delete thisCache[ name ]; + + // Support space separated names + if ( jQuery.isArray( name ) ) { + name = name; + } else if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed - if ( !isEmptyDataObject(thisCache) ) { + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { return; } } } // See jQuery.data for more information - if ( pvt ) { - delete cache[ id ][ internalKey ]; + if ( !pvt ) { + delete cache[ id ].data; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it @@ -1469,34 +1867,19 @@ jQuery.extend({ } } - var internalCache = cache[ id ][ internalKey ]; - // Browsers that fail expando deletion also refuse to delete expandos on // the window, but it will allow it on all other JS objects; other browsers // don't care - if ( jQuery.support.deleteExpando || cache != window ) { + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { delete cache[ id ]; } else { cache[ id ] = null; } - // We destroyed the entire user cache at once because it's faster than - // iterating through each key, but we need to continue to persist internal - // data if it existed - if ( internalCache ) { - cache[ id ] = {}; - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - - cache[ id ][ internalKey ] = internalCache; - - // Otherwise, we need to eliminate the expando on the node to avoid + // We destroyed the cache and need to eliminate the expando on the node to avoid // false lookups in the cache for entries that no longer exist - } else if ( isNode ) { + if ( isNode ) { // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases @@ -1531,22 +1914,25 @@ jQuery.extend({ jQuery.fn.extend({ data: function( key, value ) { - var data = null; + var parts, attr, name, + data = null; if ( typeof key === "undefined" ) { if ( this.length ) { data = jQuery.data( this[0] ); - if ( this[0].nodeType === 1 ) { - var attr = this[0].attributes, name; + if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) { + attr = this[0].attributes; for ( var i = 0, l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { - name = name.substr( 5 ); + name = jQuery.camelCase( name.substring(5) ); + dataAttr( this[0], name, data[ name ] ); } } + jQuery._data( this[0], "parsedAttrs", true ); } } @@ -1558,7 +1944,7 @@ jQuery.fn.extend({ }); } - var parts = key.split("."); + parts = key.split("."); parts[1] = parts[1] ? "." + parts[1] : ""; if ( value === undefined ) { @@ -1597,14 +1983,17 @@ function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { - data = elem.getAttribute( "data-" + key ); + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : - !jQuery.isNaN( data ) ? parseFloat( data ) : + jQuery.isNumeric( data ) ? parseFloat( data ) : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} @@ -1620,11 +2009,14 @@ function dataAttr( elem, key, data ) { return data; } -// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON -// property to be considered empty objects; this property always exists in -// order to make sure JSON.stringify does not expose internal metadata +// checks a cache object for emptiness function isEmptyDataObject( obj ) { for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } if ( name !== "toJSON" ) { return false; } @@ -1636,35 +2028,78 @@ function isEmptyDataObject( obj ) { +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + jQuery.extend({ - queue: function( elem, type, data ) { - if ( !elem ) { - return; - } - type = (type || "fx") + "queue"; - var q = jQuery._data( elem, type ); + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, - // Speed up dequeue by getting out quickly if this is just a lookup - if ( !data ) { - return q || []; + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } } + }, - if ( !q || jQuery.isArray(data) ) { - q = jQuery._data( elem, type, jQuery.makeArray(data) ); + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); - } else { - q.push( data ); + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; } - - return q; }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), - fn = queue.shift(); + fn = queue.shift(), + hooks = {}; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { @@ -1675,16 +2110,18 @@ jQuery.extend({ // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { - queue.unshift("inprogress"); + queue.unshift( "inprogress" ); } - fn.call(elem, function() { - jQuery.dequeue(elem, type); - }); + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); } if ( !queue.length ) { - jQuery.removeData( elem, type + "queue", true ); + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); } } }); @@ -1699,7 +2136,7 @@ jQuery.fn.extend({ if ( data === undefined ) { return jQuery.queue( this[0], type ); } - return this.each(function( i ) { + return this.each(function() { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { @@ -1712,23 +2149,54 @@ jQuery.fn.extend({ jQuery.dequeue( this, type ); }); }, - // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; - return this.queue( type, function() { - var elem = this; - setTimeout(function() { - jQuery.dequeue( elem, type ); - }, time ); + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; }); }, - clearQueue: function( type ) { return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise(); } }); @@ -1736,66 +2204,67 @@ jQuery.fn.extend({ var rclass = /[\n\t\r]/g, - rspaces = /\s+/, + rspace = /\s+/, rreturn = /\r/g, - rspecialurl = /^(?:href|src|style)$/, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, - rradiocheck = /^(?:radio|checkbox)$/i; - -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, - removeAttr: function( name, fn ) { - return this.each(function(){ - jQuery.attr( this, name, "" ); - if ( this.nodeType === 1 ) { - this.removeAttribute( name ); - } + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} }); }, addClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.addClass( value.call(this, i, self.attr("class")) ); + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); }); } if ( value && typeof value === "string" ) { - var classNames = (value || "").split( rspaces ); + classNames = value.split( rspace ); - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; if ( elem.nodeType === 1 ) { - if ( !elem.className ) { + if ( !elem.className && classNames.length === 1 ) { elem.className = value; } else { - var className = " " + elem.className + " ", - setClass = elem.className; + setClass = " " + elem.className + " "; - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { - setClass += " " + classNames[c]; + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; } } elem.className = jQuery.trim( setClass ); @@ -1808,24 +2277,25 @@ jQuery.fn.extend({ }, removeClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.removeClass( value.call(this, i, self.attr("class")) ); + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); }); } if ( (value && typeof value === "string") || value === undefined ) { - var classNames = (value || "").split( rspaces ); + classNames = ( value || "" ).split( rspace ); - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { - var className = (" " + elem.className + " ").replace(rclass, " "); - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[c] + " ", " "); + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); } elem.className = jQuery.trim( className ); @@ -1844,9 +2314,8 @@ jQuery.fn.extend({ isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this); - self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } @@ -1857,7 +2326,7 @@ jQuery.fn.extend({ i = 0, self = jQuery( this ), state = stateVal, - classNames = value.split( rspaces ); + classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list @@ -1878,9 +2347,11 @@ jQuery.fn.extend({ }, hasClass: function( selector ) { - var className = " " + selector + " "; - for ( var i = 0, l = this.length; i < l; i++ ) { - if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } @@ -1889,82 +2360,42 @@ jQuery.fn.extend({ }, val: function( value ) { - if ( !arguments.length ) { - var elem = this[0]; + var hooks, ret, isFunction, + elem = this[0]; + if ( !arguments.length ) { if ( elem ) { - if ( jQuery.nodeName( elem, "option" ) ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery(option).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; - return values; + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; } - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { - return elem.getAttribute("value") === null ? "on" : elem.value; - } - - // Everything else, we just grab the value - return (elem.value || "").replace(rreturn, ""); + ret = elem.value; + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; } return undefined; } - var isFunction = jQuery.isFunction(value); + isFunction = jQuery.isFunction( value ); - return this.each(function(i) { - var self = jQuery(this), val = value; + return this.each(function( i ) { + var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { - val = value.call(this, i, self.val()); + val = value.call( this, i, self.val() ); + } else { + val = value; } // Treat null/undefined as ""; convert numbers to string @@ -1972,34 +2403,91 @@ jQuery.fn.extend({ val = ""; } else if ( typeof val === "number" ) { val += ""; - } else if ( jQuery.isArray(val) ) { - val = jQuery.map(val, function (value) { + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } - if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { - this.checked = jQuery.inArray( self.val(), val ) >= 0; + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, - } else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(val); + set: function( elem, value ) { + var values = jQuery.makeArray( value ); - jQuery( "option", this ).each(function() { + jQuery(elem).find("option").each(function() { this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; }); if ( !values.length ) { - this.selectedIndex = -1; + elem.selectedIndex = -1; } - - } else { - this.value = val; + return values; } - }); - } -}); + } + }, -jQuery.extend({ attrFn: { val: true, css: true, @@ -2012,239 +2500,479 @@ jQuery.extend({ }, attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + // don't get/set attributes on text, comment and attribute nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } if ( pass && name in jQuery.attrFn ) { - return jQuery(elem)[name](value); + return jQuery( elem )[ name ]( value ); } - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; - - // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; - - // Only do all the following if this is a node (faster for style) - if ( elem.nodeType === 1 ) { - // These attributes require special treatment - var special = rspecialurl.test( name ); - - // Safari mis-reports the default selected property of an option - // Accessing the parent's selectedIndex property fixes it - if ( name === "selected" && !jQuery.support.optSelected ) { - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - - // If applicable, access the attribute via the DOM 0 way - // 'in' checks fail in Blackberry 4.7 #6931 - if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { - if ( set ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } - - if ( value === null ) { - if ( elem.nodeType === 1 ) { - elem.removeAttribute( name ); - } - - } else { - elem[ name ] = value; - } - } - - // browsers index elements by id/name on forms, give priority to attributes. - if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { - return elem.getAttributeNode( name ).nodeValue; - } + // Fallback to prop when attributes are not supported + if ( !("getAttribute" in elem) ) { + return jQuery.prop( elem, name, value ); + } - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - if ( name === "tabIndex" ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } - return elem[ name ]; - } + if ( value !== undefined ) { - if ( !jQuery.support.style && notxml && name === "style" ) { - if ( set ) { - elem.style.cssText = "" + value; - } + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return undefined; - return elem.style.cssText; - } + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; - if ( set ) { - // convert the value to a string (all browsers do this but IE) see #1070 + } else { elem.setAttribute( name, "" + value ); + return value; } - // Ensure that missing attributes return undefined - // Blackberry 4.7 returns "" from getAttribute #6938 - if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { - return undefined; - } + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { - var attr = !jQuery.support.hrefNormalized && notxml && special ? - // Some attributes require a special call on IE - elem.getAttribute( name, 2 ) : - elem.getAttribute( name ); + ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; + return ret === null ? + undefined : + ret; } - // Handle everything which isn't a DOM element node - if ( set ) { - elem[ name ] = value; - } - return elem[ name ]; - } -}); - + }, + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, + i = 0; + if ( elem.nodeType === 1 ) { + attrNames = ( value || "" ).split( rspace ); + l = attrNames.length; -var rnamespaces = /\.(.*)$/, - rformElems = /^(?:textarea|input|select)$/i, - rperiod = /\./g, - rspace = / /g, - rescape = /[^\w\s.|`]/g, - fcleanup = function( nm ) { - return nm.replace(rescape, "\\$&"); - }; + for ( ; i < l; i++ ) { + name = attrNames[ i ].toLowerCase(); + propName = jQuery.propFix[ name ] || name; -/* - * A number of helper functions used for managing events. - * Many of the ideas behind this code originated from - * Dean Edwards' addEvent library. - */ -jQuery.event = { + // See #9699 for explanation of this approach (setting first, then removal) + jQuery.attr( elem, name, "" ); + elem.removeAttribute( getSetAttribute ? name : propName ); - // Bind an event to an element - // Original by Dean Edwards - add: function( elem, types, handler, data ) { - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && propName in elem ) { + elem[ propName ] = false; + } + } } + }, - // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) - // Minor release fix for bug #8018 - try { - // For whatever reason, IE has trouble passing the window object - // around, causing it to be cloned in the process - if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { - elem = window; + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; } } - catch ( e ) {} + }, - if ( handler === false ) { - handler = returnFalse; - } else if ( !handler ) { - // Fixes bug #7229. Fix recommended by jdalton - return; + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; } - var handleObjIn, handleObj; + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; } - // Make sure that the function being executed has a unique ID - if ( !handler.guid ) { - handler.guid = jQuery.guid++; + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } } + }); +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspaces = / /g, + rescape = /[^\w\s.|`]/g, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /\bhover(\.\S+)?/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || elem.id === m[2]) && + (!m[3] || m[3].test( elem.className )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { - // Init the element's event structure - var elemData = jQuery._data( elem ); + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; - // If no elemData is found then we must be trying to bind to one of the - // banned noData elements - if ( !elemData ) { + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { return; } - var events = elemData.events, - eventHandle = elemData.handle; + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + // Init the element's event structure and main handler, if this is the first + events = elemData.events; if ( !events ) { elemData.events = events = {}; } - + eventHandle = elemData.handle; if ( !eventHandle ) { - elemData.handle = eventHandle = function() { - // Handle the second event of a trigger and when - // an event is called after a page has unloaded - return typeof jQuery !== "undefined" && !jQuery.event.triggered ? - jQuery.event.handle.apply( eventHandle.elem, arguments ) : + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; } - // Add elem as a property of the handle function - // This is to prevent a memory leak with non-native events in IE. - eventHandle.elem = elem; - // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); - types = types.split(" "); + types = hoverHack(types).split( " " ); + for ( t = 0; t < types.length; t++ ) { - var type, i = 0, namespaces; + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); - while ( (type = types[ i++ ]) ) { - handleObj = handleObjIn ? - jQuery.extend({}, handleObjIn) : - { handler: handler, data: data }; + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; - // Namespaced event handlers - if ( type.indexOf(".") > -1 ) { - namespaces = type.split("."); - type = namespaces.shift(); - handleObj.namespace = namespaces.slice(0).sort().join("."); + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; - } else { - namespaces = []; - handleObj.namespace = ""; - } + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; - handleObj.type = type; - if ( !handleObj.guid ) { - handleObj.guid = handler.guid; - } + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + namespace: namespaces.join(".") + }, handleObjIn ); - // Get the current list of functions bound to this event - var handlers = events[ type ], - special = jQuery.event.special[ type ] || {}; + // Delegated event; pre-analyze selector so it's processed quickly on event dispatch + if ( selector ) { + handleObj.quick = quickParse( selector ); + if ( !handleObj.quick && jQuery.expr.match.POS.test( selector ) ) { + handleObj.isPositional = true; + } + } - // Init the event handler queue + // Init the event handler queue if we're the first + handlers = events[ type ]; if ( !handlers ) { handlers = events[ type ] = []; + handlers.delegateCount = 0; - // Check for a special event handler - // Only use addEventListener/attachEvent if the special - // events handler returns false + // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { @@ -2264,10 +2992,14 @@ jQuery.event = { } } - // Add the function to the element's handler list - handlers.push( handleObj ); + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } - // Keep track of which events have been used, for global triggering + // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } @@ -2278,288 +3010,313 @@ jQuery.event = { global: {}, // Detach an event or set of events from an element - remove: function( elem, types, handler, pos ) { - // don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - if ( handler === false ) { - handler = returnFalse; - } + remove: function( elem, types, handler, selector ) { - var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ), - events = elemData && elemData.events; + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, namespaces, origCount, + j, events, special, handle, eventType, handleObj; - if ( !elemData || !events ) { + if ( !elemData || !(events = elemData.events) ) { return; } - // types is actually an event object here - if ( types && types.type ) { - handler = types.handler; - types = types.type; - } - - // Unbind all events for the element - if ( !types || typeof types === "string" && types.charAt(0) === "." ) { - types = types || ""; - - for ( type in events ) { - jQuery.event.remove( elem, type + types ); - } - - return; - } - - // Handle multiple events separated by a space - // jQuery(...).unbind("mouseover mouseout", fn); - types = types.split(" "); - - while ( (type = types[ i++ ]) ) { - origType = type; - handleObj = null; - all = type.indexOf(".") < 0; - namespaces = []; - - if ( !all ) { - // Namespaced event handlers - namespaces = type.split("."); - type = namespaces.shift(); - - namespace = new RegExp("(^|\\.)" + - jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - eventType = events[ type ]; - - if ( !eventType ) { - continue; - } - - if ( !handler ) { - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; + // Once for each type.namespace in types; type may be omitted + types = hoverHack( types || "" ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = tns[2]; - if ( all || namespace.test( handleObj.namespace ) ) { - jQuery.event.remove( elem, origType, handleObj.handler, j ); - eventType.splice( j--, 1 ); - } + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + namespaces = namespaces? "." + namespaces : ""; + for ( j in events ) { + jQuery.event.remove( elem, j + namespaces, handler, selector ); } - - continue; + return; } special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - for ( j = pos || 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; + // Only need to loop for special events or selective removal + if ( handler || namespaces || selector || special.remove ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; - if ( handler.guid === handleObj.guid ) { - // remove the given handler for the given type - if ( all || namespace.test( handleObj.namespace ) ) { - if ( pos == null ) { - eventType.splice( j--, 1 ); - } + if ( !handler || handler.guid === handleObj.guid ) { + if ( !namespaces || namespaces.test( handleObj.namespace ) ) { + if ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) { + eventType.splice( j--, 1 ); - if ( special.remove ) { - special.remove.call( elem, handleObj ); + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } } } - - if ( pos != null ) { - break; - } } + } else { + // Removing all events + eventType.length = 0; } - // remove generic event handler if no more handlers exist - if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } - ret = null; delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { - var handle = elemData.handle; + handle = elemData.handle; if ( handle ) { handle.elem = null; } - delete elemData.events; - delete elemData.handle; - - if ( jQuery.isEmptyObject( elemData ) ) { - jQuery.removeData( elem, undefined, true ); - } + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); } }, - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + // Event object or event type var type = event.type || event, - bubbling = arguments[3]; + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; - if ( !bubbling ) { - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } - if ( type.indexOf("!") >= 0 ) { - event.type = type = type.slice(0, -1); - event.exclusive = true; - } + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); - - // Only trigger if we've ever bound an event for it - if ( jQuery.event.global[ type ] ) { - // XXX This code smells terrible. event.js should not be directly - // inspecting the data cache - jQuery.each( jQuery.cache, function() { - // internalKey variable is just used to make it easier to find - // and potentially change this stuff later; currently it just - // points to jQuery.expando - var internalKey = jQuery.expando, - internalCache = this[ internalKey ]; - if ( internalCache && internalCache.events && internalCache.events[ type ] ) { - jQuery.event.trigger( event, data, internalCache.handle.elem ); - } - }); - } - } + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } - // Handle triggering a single element + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // triggerHandler() and global events don't bubble or run the default action + if ( onlyHandlers || !elem ) { + event.preventDefault(); + } - // don't do events on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } } + return; + } - // Clean up in case it is reused - event.result = undefined; + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); - // Clone the incoming data, if any - data = jQuery.makeArray( data ); - data.unshift( event ); + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; } - event.currentTarget = elem; + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - // Trigger the event, it is assumed that "handle" is a function - var handle = jQuery._data( elem, "handle" ); + bubbleType = special.delegateType || type; + old = null; + for ( cur = elem.parentNode; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } - if ( handle ) { - handle.apply( elem, data ); + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } } - var parent = elem.parentNode || elem.ownerDocument; + // Fire handlers on the event path + for ( i = 0; i < eventPath.length; i++ ) { - // Trigger an inline bound script - try { - if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { - if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { - event.result = false; - event.preventDefault(); - } - } + cur = eventPath[i][0]; + event.type = eventPath[i][1]; - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (inlineError) {} + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) ) { + handle.apply( cur, data ); + } - if ( !event.isPropagationStopped() && parent ) { - jQuery.event.trigger( event, data, parent, true ); + if ( event.isPropagationStopped() ) { + break; + } + } + event.type = type; - } else if ( !event.isDefaultPrevented() ) { - var old, - target = event.target, - targetType = type.replace( rnamespaces, "" ), - isClick = jQuery.nodeName( target, "a" ) && targetType === "click", - special = jQuery.event.special[ targetType ] || {}; + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { - if ( (!special._default || special._default.call( elem, event ) === false) && - !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - try { - if ( target[ targetType ] ) { - // Make sure that we don't accidentally re-trigger the onFOO events - old = target[ "on" + targetType ]; + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - if ( old ) { - target[ "on" + targetType ] = null; - } + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; - jQuery.event.triggered = true; - target[ targetType ](); + if ( old ) { + elem[ ontype ] = null; } - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (triggerError) {} + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; - if ( old ) { - target[ "on" + targetType ] = old; + if ( old ) { + elem[ ontype ] = old; + } } - - jQuery.event.triggered = false; } } - }, - - handle: function( event ) { - var all, handlers, namespaces, namespace_re, events, - namespace_sort = [], - args = jQuery.makeArray( arguments ); - event = args[0] = jQuery.event.fix( event || window.event ); - event.currentTarget = this; - - // Namespaced event handlers - all = event.type.indexOf(".") < 0 && !event.exclusive; + return event.result; + }, - if ( !all ) { - namespaces = event.type.split("."); - event.type = namespaces.shift(); - namespace_sort = namespaces.slice(0).sort(); - namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + specialHandle = ( jQuery.event.special[ event.type ] || {} ).handle, + handlerQueue = [], + i, j, cur, ret, selMatch, matched, matches, handleObj, sel, hit, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Determine handlers that should run if there are delegated events + // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) { + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + selMatch = {}; + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + hit = selMatch[ sel ]; + + if ( handleObj.isPositional ) { + // Since .is() does not work for positionals; see http://jsfiddle.net/eJ4yd/3/ + hit = ( hit || (selMatch[ sel ] = jQuery( sel )) ).index( cur ) >= 0; + } else if ( hit === undefined ) { + hit = selMatch[ sel ] = ( handleObj.quick ? quickIs( cur, handleObj.quick ) : jQuery( cur ).is( sel ) ); + } + if ( hit ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } } - event.namespace = event.namespace || namespace_sort.join("."); - - events = jQuery._data(this, "events"); + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } - handlers = (events || {})[ event.type ]; + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; - if ( events && handlers ) { - // Clone the handlers to prevent manipulation - handlers = handlers.slice(0); + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - // Filter the functions by class - if ( all || namespace_re.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; event.data = handleObj.data; event.handleObj = handleObj; - var ret = handleObj.handler.apply( this, args ); + ret = ( specialHandle || handleObj.handler ).apply( matched.elem, args ); if ( ret !== undefined ) { event.result = ret; @@ -2568,10 +3325,6 @@ jQuery.event = { event.stopPropagation(); } } - - if ( event.isImmediatePropagationStopped() ) { - break; - } } } } @@ -2579,90 +3332,106 @@ jQuery.event = { return event.result; }, - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement wheelDelta".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } - // store a copy of the original event object - // and "clone" to set read-only properties - var originalEvent = event; + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + event = jQuery.Event( originalEvent ); - for ( var i = this.props.length, prop; i; ) { - prop = this.props[ --i ]; + for ( i = copy.length; i; ) { + prop = copy[ --i ]; event[ prop ] = originalEvent[ prop ]; } - // Fix target property, if necessary + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) if ( !event.target ) { - // Fixes #1925 where srcElement might not be defined either - event.target = event.srcElement || document; + event.target = originalEvent.srcElement || document; } - // check if target is a textnode (safari) + // Target should not be a text node (#504, Safari) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) { - event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, - body = document.body; - - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } - - // Add which for key events - if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { - event.which = event.charCode != null ? event.charCode : event.keyCode; - } - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) { + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { event.metaKey = event.ctrlKey; } - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button !== undefined ) { - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - } - - return event; + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; }, - // Deprecated, use jQuery.guid instead - guid: 1E8, - - // Deprecated, use jQuery.proxy instead - proxy: jQuery.proxy, - special: { ready: { // Make sure the ready event is setup - setup: jQuery.bindReady, - teardown: jQuery.noop + setup: jQuery.bindReady }, - live: { - add: function( handleObj ) { - jQuery.event.add( this, - liveConvert( handleObj.origType, handleObj.selector ), - jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); - }, - - remove: function( handleObj ) { - jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); - } + focus: { + delegateType: "focusin", + noBubble: true + }, + blur: { + delegateType: "focusout", + noBubble: true }, beforeunload: { @@ -2679,9 +3448,35 @@ jQuery.event = { } } } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } } }; +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { @@ -2694,10 +3489,10 @@ jQuery.removeEvent = document.removeEventListener ? } }; -jQuery.Event = function( src ) { +jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword - if ( !this.preventDefault ) { - return new jQuery.Event( src ); + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); } // Event object @@ -2707,17 +3502,21 @@ jQuery.Event = function( src ) { // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; // Event type } else { this.type = src; } - // timeStamp is buggy for some events on Firefox(#3843) - // So we won't rely on the native value - this.timeStamp = jQuery.now(); + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; @@ -2773,303 +3572,270 @@ jQuery.Event.prototype = { isImmediatePropagationStopped: returnFalse }; -// Checks if an event happened on an element within another element -// Used in jQuery.event.special.mouseenter and mouseleave handlers -var withinElement = function( event ) { - // Check if mouse(over|out) are still within the same parent element - var parent = event.relatedTarget; - - // Firefox sometimes assigns relatedTarget a XUL element - // which we cannot access the parentNode property of - try { - - // Chrome does something similar, the parentNode property - // can be accessed but is null. - if ( parent !== document && !parent.parentNode ) { - return; - } - // Traverse up the tree - while ( parent && parent !== this ) { - parent = parent.parentNode; - } - - if ( parent !== this ) { - // set the correct event type - event.type = event.data; - - // handle event if we actually just moused on to a non sub-element - jQuery.event.handle.apply( this, arguments ); - } - - // assuming we've left the element since we most likely mousedover a xul element - } catch(e) { } -}, - -// In case of event delegation, we only need to rename the event.type, -// liveHandler will take care of the rest. -delegate = function( event ) { - event.type = event.data; - jQuery.event.handle.apply( this, arguments ); -}; - -// Create mouseenter and mouseleave events +// Create mouseenter/leave events using mouseover/out and event-time checks jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { - jQuery.event.special[ orig ] = { - setup: function( data ) { - jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); - }, - teardown: function( data ) { - jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + jQuery.event.special[ orig ] = jQuery.event.special[ fix ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + oldType, ret; + + // For a real mouseover/out, always call the handler; for + // mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || handleObj.origType === event.type || (related !== target && !jQuery.contains( target, related )) ) { + oldType = event.type; + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = oldType; + } + return ret; } }; }); -// submit delegation +// IE submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { - setup: function( data, namespaces ) { - if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { - jQuery.event.add(this, "click.specialSubmit", function( e ) { - var elem = e.target, - type = elem.type; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - trigger( "submit", this, arguments ); - } - }); - - jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, - type = elem.type; + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - trigger( "submit", this, arguments ); - } - }); + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + // Form was submitted, bubble the event up the tree + if ( this.parentNode ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener + }, - } else { + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { return false; } - }, - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialSubmit" ); + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); } }; - } -// change delegation, happens here so we have bind. +// IE change delegation and checkbox/radio fix if ( !jQuery.support.changeBubbles ) { - var changeFilters, - - getVal = function( elem ) { - var type = elem.type, val = elem.value; - - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; - - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; - - } else if ( elem.nodeName.toLowerCase() === "select" ) { - val = elem.selectedIndex; - } - - return val; - }, - - testChange = function testChange( e ) { - var elem = e.target, data, val; - - if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { - return; - } - - data = jQuery._data( elem, "_change_data" ); - val = getVal(elem); - - // the current data will be also retrieved by beforeactivate - if ( e.type !== "focusout" || elem.type !== "radio" ) { - jQuery._data( elem, "_change_data", val ); - } - - if ( data === undefined || val === data ) { - return; - } - - if ( data != null || val ) { - e.type = "change"; - e.liveFired = undefined; - jQuery.event.trigger( e, arguments[1], elem ); - } - }; - jQuery.event.special.change = { - filters: { - focusout: testChange, - - beforedeactivate: testChange, - click: function( e ) { - var elem = e.target, type = elem.type; + setup: function() { - if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { - testChange.call( this, e ); + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); } - }, - - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = elem.type; + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; - if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - testChange.call( this, e ); + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; } - }, - - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information - beforeactivate: function( e ) { - var elem = e.target; - jQuery._data( elem, "_change_data", getVal(elem) ); - } + }); }, - setup: function( data, namespaces ) { - if ( this.type === "file" ) { - return false; - } + handle: function( event ) { + var elem = event.target; - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); } - - return rformElems.test( this.nodeName ); }, - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialChange" ); + teardown: function() { + jQuery.event.remove( this, "._change" ); return rformElems.test( this.nodeName ); } }; - - changeFilters = jQuery.event.special.change.filters; - - // Handle when the input is .focus()'d - changeFilters.focus = changeFilters.beforeactivate; -} - -function trigger( type, elem, args ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - // Don't pass args or remember liveFired; they apply to the donor event. - var event = jQuery.extend( {}, args[ 0 ] ); - event.type = type; - event.originalEvent = {}; - event.liveFired = undefined; - jQuery.event.handle.call( elem, event ); - if ( event.isDefaultPrevented() ) { - args[ 0 ].preventDefault(); - } } // Create "bubbling" focus and blur events -if ( document.addEventListener ) { +if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + jQuery.event.special[ fix ] = { setup: function() { - this.addEventListener( orig, handler, true ); + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } }, teardown: function() { - this.removeEventListener( orig, handler, true ); + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } } }; - - function handler( e ) { - e = jQuery.event.fix( e ); - e.type = fix; - return jQuery.event.handle.call( this, e ); - } }); } -jQuery.each(["bind", "one"], function( i, name ) { - jQuery.fn[ name ] = function( type, data, fn ) { - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ name ](key, data, type[key], fn); - } - return this; - } - - if ( jQuery.isFunction( data ) || data === false ) { - fn = data; - data = undefined; - } - - var handler = name === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; +jQuery.fn.extend({ - if ( type === "unload" && name !== "one" ) { - this.one( type, data, fn ); + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.add( this[i], type, handler, data ); + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = selector; + selector = undefined; } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; } - return this; - }; -}); - -jQuery.fn.extend({ - unbind: function( type, fn ) { - // Handle object literals - if ( typeof type === "object" && !type.preventDefault ) { - for ( var key in type ) { - this.unbind(key, type[key]); + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.remove( this[i], type, fn ); + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on.call( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); } + return this; } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); return this; }, delegate: function( selector, types, data, fn ) { - return this.live( types, data, fn, selector ); + return this.on( types, selector, data, fn ); }, - undelegate: function( selector, types, fn ) { - if ( arguments.length === 0 ) { - return this.unbind( "live" ); - - } else { - return this.die( types, null, fn, selector ); - } + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); }, trigger: function( type, data ) { @@ -3077,38 +3843,36 @@ jQuery.fn.extend({ jQuery.event.trigger( type, data, this ); }); }, - triggerHandler: function( type, data ) { if ( this[0] ) { - var event = jQuery.Event( type ); - event.preventDefault(); - event.stopPropagation(); - jQuery.event.trigger( event, data, this[0] ); - return event.result; + return jQuery.event.trigger( type, data, this[0], true ); } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, - i = 1; + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; while ( i < args.length ) { - jQuery.proxy( fn, args[ i++ ] ); + args[ i++ ].guid = guid; } - return this.click( jQuery.proxy( fn, function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - })); + return this.click( toggler ); }, hover: function( fnOver, fnOut ) { @@ -3116,165 +3880,9 @@ jQuery.fn.extend({ } }); -var liveMap = { - focus: "focusin", - blur: "focusout", - mouseenter: "mouseover", - mouseleave: "mouseout" -}; - -jQuery.each(["live", "die"], function( i, name ) { - jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { - var type, i = 0, match, namespaces, preType, - selector = origSelector || this.selector, - context = origSelector ? this : jQuery( this.context ); - - if ( typeof types === "object" && !types.preventDefault ) { - for ( var key in types ) { - context[ name ]( key, data, types[key], selector ); - } - - return this; - } - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - types = (types || "").split(" "); - - while ( (type = types[ i++ ]) != null ) { - match = rnamespaces.exec( type ); - namespaces = ""; - - if ( match ) { - namespaces = match[0]; - type = type.replace( rnamespaces, "" ); - } - - if ( type === "hover" ) { - types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); - continue; - } - - preType = type; - - if ( type === "focus" || type === "blur" ) { - types.push( liveMap[ type ] + namespaces ); - type = type + namespaces; - - } else { - type = (liveMap[ type ] || type) + namespaces; - } - - if ( name === "live" ) { - // bind live handler - for ( var j = 0, l = context.length; j < l; j++ ) { - jQuery.event.add( context[j], "live." + liveConvert( type, selector ), - { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); - } - - } else { - // unbind live handler - context.unbind( "live." + liveConvert( type, selector ), fn ); - } - } - - return this; - }; -}); - -function liveHandler( event ) { - var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, - elems = [], - selectors = [], - events = jQuery._data( this, "events" ); - - // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) - if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { - return; - } - - if ( event.namespace ) { - namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - event.liveFired = this; - - var live = events.live.slice(0); - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { - selectors.push( handleObj.selector ); - - } else { - live.splice( j--, 1 ); - } - } - - match = jQuery( event.target ).closest( selectors, event.currentTarget ); - - for ( i = 0, l = match.length; i < l; i++ ) { - close = match[i]; - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { - elem = close.elem; - related = null; - - // Those two events require additional checking - if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { - event.type = handleObj.preType; - related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; - } - - if ( !related || related !== elem ) { - elems.push({ elem: elem, handleObj: handleObj, level: close.level }); - } - } - } - } - - for ( i = 0, l = elems.length; i < l; i++ ) { - match = elems[i]; - - if ( maxLevel && match.level > maxLevel ) { - break; - } - - event.currentTarget = match.elem; - event.data = match.handleObj.data; - event.handleObj = match.handleObj; - - ret = match.handleObj.origHandler.apply( match.elem, arguments ); - - if ( ret === false || event.isPropagationStopped() ) { - maxLevel = match.level; - - if ( ret === false ) { - stop = false; - } - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - - return stop; -} - -function liveConvert( type, selector ) { - return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); -} - jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { @@ -3291,9 +3899,18 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl if ( jQuery.attrFn ) { jQuery.attrFn[ name ] = true; } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } }); + /*! * Sizzle CSS Selector Engine * Copyright 2011, The Dojo Foundation @@ -3303,11 +3920,13 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true, rBackslash = /\\/g, + rReturn = /\r\n/g, rNonWord = /\W/; // Here we check if the JavaScript engine is using some sort of @@ -3359,7 +3978,7 @@ var Sizzle = function( selector, context, results, seed ) { if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); + set = posProcess( parts[0] + parts[1], context, seed ); } else { set = Expr.relative[ parts[0] ] ? @@ -3373,7 +3992,7 @@ var Sizzle = function( selector, context, results, seed ) { selector += parts.shift(); } - set = posProcess( selector, set ); + set = posProcess( selector, set, seed ); } } @@ -3492,18 +4111,17 @@ Sizzle.matchesSelector = function( node, expr ) { }; Sizzle.find = function( expr, context, isXML ) { - var set; + var set, i, len, match, type, left; if ( !expr ) { return []; } - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var match, - type = Expr.order[i]; + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; + left = match[1]; match.splice( 1, 1 ); if ( left.substr( left.length - 1 ) !== "\\" ) { @@ -3529,17 +4147,18 @@ Sizzle.find = function( expr, context, isXML ) { Sizzle.filter = function( expr, set, inplace, not ) { var match, anyFound, + type, found, item, filter, left, + i, pass, old = expr, result = [], curLoop = set, isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); while ( expr && set.length ) { - for ( var type in Expr.filter ) { + for ( type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var found, item, - filter = Expr.filter[ type ], - left = match[1]; + filter = Expr.filter[ type ]; + left = match[1]; anyFound = false; @@ -3565,10 +4184,10 @@ Sizzle.filter = function( expr, set, inplace, not ) { } if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; + pass = not ^ found; if ( inplace && found != null ) { if ( pass ) { @@ -3622,6 +4241,45 @@ Sizzle.error = function( msg ) { throw "Syntax error, unrecognized expression: " + msg; }; +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], @@ -3918,43 +4576,53 @@ var Expr = Sizzle.selectors = { }, text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case - return "text" === elem.getAttribute( 'type' ); + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, + radio: function( elem ) { - return "radio" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; }, checkbox: function( elem ) { - return "checkbox" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; }, file: function( elem ) { - return "file" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; }, + password: function( elem ) { - return "password" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; }, submit: function( elem ) { - return "submit" === elem.type; + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; }, image: function( elem ) { - return "image" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; }, reset: function( elem ) { - return "reset" === elem.type; + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; }, button: function( elem ) { - return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; }, input: function( elem ) { return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; } }, setFilters: { @@ -3999,7 +4667,7 @@ var Expr = Sizzle.selectors = { return filter( elem, i, match, array ); } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; @@ -4018,7 +4686,10 @@ var Expr = Sizzle.selectors = { }, CHILD: function( elem, match ) { - var type = match[1], + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], node = elem; switch ( type ) { @@ -4046,18 +4717,18 @@ var Expr = Sizzle.selectors = { return true; case "nth": - var first = match[2], - last = match[3]; + first = match[2]; + last = match[3]; if ( first === 1 && last === 0 ) { return true; } - var doneName = match[0], - parent = elem.parentNode; + doneName = match[0]; + parent = elem.parentNode; - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { @@ -4065,10 +4736,10 @@ var Expr = Sizzle.selectors = { } } - parent.sizcache = doneName; + parent[ expando ] = doneName; } - var diff = elem.nodeIndex - last; + diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; @@ -4084,7 +4755,7 @@ var Expr = Sizzle.selectors = { }, TAG: function( elem, match ) { - return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; }, CLASS: function( elem, match ) { @@ -4094,7 +4765,9 @@ var Expr = Sizzle.selectors = { ATTR: function( elem, match ) { var name = match[1], - result = Expr.attrHandle[ name ] ? + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : @@ -4105,6 +4778,8 @@ var Expr = Sizzle.selectors = { return result == null ? type === "!=" : + !type && Sizzle.attr ? + result != null : type === "=" ? value === check : type === "*=" ? @@ -4207,6 +4882,16 @@ if ( document.documentElement.compareDocumentPosition ) { } else { sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + var al, bl, ap = [], bp = [], @@ -4214,13 +4899,8 @@ if ( document.documentElement.compareDocumentPosition ) { bup = b.parentNode, cur = aup; - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - // If the nodes are siblings (or identical) we can do a quick check - } else if ( aup === bup ) { + if ( aup === bup ) { return siblingCheck( a, b ); // If no parents were found then the nodes are disconnected @@ -4280,26 +4960,6 @@ if ( document.documentElement.compareDocumentPosition ) { }; } -// Utility function for retreiving the text value of an array of DOM nodes -Sizzle.getText = function( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += Sizzle.getText( elem.childNodes ); - } - } - - return ret; -}; - // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ @@ -4496,19 +5156,23 @@ if ( document.querySelectorAll ) { (function(){ var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, - pseudoWorks = false; + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); - } catch( pseudoError ) { - pseudoWorks = true; - } + } catch( pseudoError ) { + pseudoWorks = true; + } - if ( matches ) { Sizzle.matchesSelector = function( node, expr ) { // Make sure that attribute selectors are quoted expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); @@ -4516,7 +5180,15 @@ if ( document.querySelectorAll ) { if ( !Sizzle.isXML( node ) ) { try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - return matches.call( node, expr ); + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } } } catch(e) {} } @@ -4565,13 +5237,13 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { elem = elem[dir]; while ( elem ) { - if ( elem.sizcache === doneName ) { + if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; + elem[ expando ] = doneName; elem.sizset = i; } @@ -4598,14 +5270,14 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { elem = elem[dir]; while ( elem ) { - if ( elem.sizcache === doneName ) { + if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { - elem.sizcache = doneName; + elem[ expando ] = doneName; elem.sizset = i; } @@ -4653,7 +5325,7 @@ Sizzle.isXML = function( elem ) { return documentElement ? documentElement.nodeName !== "HTML" : false; }; -var posProcess = function( selector, context ) { +var posProcess = function( selector, context, seed ) { var match, tmpSet = [], later = "", @@ -4669,13 +5341,16 @@ var posProcess = function( selector, context ) { selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); + Sizzle( selector, root[i], tmpSet, seed ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; @@ -4705,17 +5380,30 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + var ret = this.pushStack( "", "find", selector ), - length = 0; + length, n, r; - for ( var i = 0, l = this.length; i < l; i++ ) { + for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique - for ( var n = length; n < ret.length; n++ ) { - for ( var r = 0; r < length; r++ ) { + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; @@ -4748,47 +5436,42 @@ jQuery.fn.extend({ }, is: function( selector ) { - return !!selector && jQuery.filter( selector, this ).length > 0; + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; - + + // Array (deprecated as of jQuery 1.7) if ( jQuery.isArray( selectors ) ) { - var match, selector, - matches = {}, - level = 1; - - if ( cur && selectors.length ) { - for ( i = 0, l = selectors.length; i < l; i++ ) { - selector = selectors[i]; - - if ( !matches[selector] ) { - matches[selector] = jQuery.expr.match.POS.test( selector ) ? - jQuery( selector, context || this.context ) : - selector; - } - } + var level = 1; - while ( cur && cur.ownerDocument && cur !== context ) { - for ( selector in matches ) { - match = matches[selector]; + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { - if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { - ret.push({ selector: selector, elem: cur, level: level }); - } + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); } - - cur = cur.parentNode; - level++; } + + cur = cur.parentNode; + level++; } return ret; } - var pos = POS.test( selectors ) ? - jQuery( selectors, context || this.context ) : null; + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; @@ -4800,14 +5483,14 @@ jQuery.fn.extend({ } else { cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context ) { + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } } } - ret = ret.length > 1 ? jQuery.unique(ret) : ret; + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, @@ -4815,12 +5498,17 @@ jQuery.fn.extend({ // Determine the position of an element within // the matched set of elements index: function( elem ) { - if ( !elem || typeof elem === "string" ) { - return jQuery.inArray( this[0], - // If it receives a string, the selector is used - // If it receives nothing, the siblings are used - elem ? jQuery( elem ) : this.parent().children() ); + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); } + // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used @@ -4830,7 +5518,7 @@ jQuery.fn.extend({ add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : - jQuery.makeArray( selector ), + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? @@ -4968,6 +5656,11 @@ jQuery.extend({ // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); @@ -4976,7 +5669,7 @@ function winnow( elements, qualifier, keep ) { } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { - return (elem === qualifier) === keep; + return ( elem === qualifier ) === keep; }); } else if ( typeof qualifier === "string" ) { @@ -4992,22 +5685,42 @@ function winnow( elements, qualifier, keep ) { } return jQuery.grep(elements, function( elem, i ) { - return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; }); } -var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, +function createSafeFragment( document ) { + var list = nodeNames.split( " " ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr article aside audio canvas datalist details figcaption figure footer " + + "header hgroup mark meter nav output progress section summary time video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, rtagName = /<([\w:]+)/, rtbody = /", "" ], legend: [ 1, "
", "
" ], @@ -5017,7 +5730,8 @@ var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, col: [ 2, "", "
" ], area: [ 1, "", "" ], _default: [ 0, "", "" ] - }; + }, + safeFragment = createSafeFragment( document ); wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; @@ -5068,7 +5782,7 @@ jQuery.fn.extend({ } return elem; - }).append(this); + }).append( this ); } return this; @@ -5198,7 +5912,7 @@ jQuery.fn.extend({ null; // See if we can take a shortcut and just use innerHTML - } else if ( typeof value === "string" && !rnocache.test( value ) && + } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) && (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) && !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) { @@ -5260,7 +5974,9 @@ jQuery.fn.extend({ } }); } else { - return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ); + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; } }, @@ -5322,7 +6038,7 @@ jQuery.fn.extend({ // in certain situations (Bug #8070). // Fragments from the fragment cache must always be cloned and never used // in place. - results.cacheable || (l > 1 && i < lastIndex) ? + results.cacheable || ( l > 1 && i < lastIndex ) ? jQuery.clone( fragment, true, true ) : fragment ); @@ -5351,44 +6067,49 @@ function cloneCopyEvent( src, dest ) { return; } - var internalKey = jQuery.expando, - oldData = jQuery.data( src ), - curData = jQuery.data( dest, oldData ); + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; - // Switch to use the internal data object, if it exists, for the next - // stage of data copying - if ( (oldData = oldData[ internalKey ]) ) { - var events = oldData.events; - curData = curData[ internalKey ] = jQuery.extend({}, oldData); + if ( events ) { + delete curData.handle; + curData.events = {}; - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( var type in events ) { - for ( var i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data ); - } + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data ); } } } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } } -function cloneFixAttributes(src, dest) { +function cloneFixAttributes( src, dest ) { + var nodeName; + // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; } - var nodeName = dest.nodeName.toLowerCase(); - // clearAttributes removes the attributes, which we don't want, // but also removes the attachEvent events, which we *do* want - dest.clearAttributes(); + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } // mergeAttributes, in contrast, only merges back on the // original attributes, not the events - dest.mergeAttributes(src); + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); // IE6-8 fail to clone children inside object elements that use // the proprietary classid attribute value (rather than the type @@ -5427,22 +6148,38 @@ function cloneFixAttributes(src, dest) { } jQuery.buildFragment = function( args, nodes, scripts ) { - var fragment, cacheable, cacheresults, - doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document); + var fragment, cacheable, cacheresults, doc, + first = args[ 0 ]; + + // nodes may contain either an explicit document object, + // a jQuery collection or context object. + // If nodes[0] contains a valid object to assign to doc + if ( nodes && nodes[0] ) { + doc = nodes[0].ownerDocument || nodes[0]; + } + + // Ensure that an attr object doesn't incorrectly stand in as a document object + // Chrome and Firefox seem to allow this to occur and will throw exception + // Fixes #8950 + if ( !doc.createDocumentFragment ) { + doc = document; + } // Only cache "small" (1/2 KB) HTML strings that are associated with the main document // Cloning options loses the selected state, so don't cache them // IE 6 doesn't like it when you put or elements in a fragment // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document && - args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) { + // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 + if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document && + first.charAt(0) === "<" && !rnocache.test( first ) && + (jQuery.support.checkClone || !rchecked.test( first )) && + (!jQuery.support.unknownElems && rnoshimcache.test( first )) ) { cacheable = true; - cacheresults = jQuery.fragments[ args[0] ]; - if ( cacheresults ) { - if ( cacheresults !== 1 ) { - fragment = cacheresults; - } + + cacheresults = jQuery.fragments[ first ]; + if ( cacheresults && cacheresults !== 1 ) { + fragment = cacheresults; } } @@ -5452,7 +6189,7 @@ jQuery.buildFragment = function( args, nodes, scripts ) { } if ( cacheable ) { - jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1; + jQuery.fragments[ first ] = cacheresults ? fragment : 1; } return { fragment: fragment, cacheable: cacheable }; @@ -5478,7 +6215,7 @@ jQuery.each({ } else { for ( var i = 0, l = insert.length; i < l; i++ ) { - var elems = (i > 0 ? this.clone(true) : this).get(); + var elems = ( i > 0 ? this.clone(true) : this ).get(); jQuery( insert[i] )[ original ]( elems ); ret = ret.concat( elems ); } @@ -5489,10 +6226,10 @@ jQuery.each({ }); function getAll( elem ) { - if ( "getElementsByTagName" in elem ) { + if ( typeof elem.getElementsByTagName !== "undefined" ) { return elem.getElementsByTagName( "*" ); - - } else if ( "querySelectorAll" in elem ) { + + } else if ( typeof elem.querySelectorAll !== "undefined" ) { return elem.querySelectorAll( "*" ); } else { @@ -5500,6 +6237,23 @@ function getAll( elem ) { } } +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( elem.type === "checkbox" || elem.type === "radio" ) { + elem.defaultChecked = elem.checked; + } +} +// Finds all inputs and passes them to fixDefaultChecked +function findInputs( elem ) { + var nodeName = ( elem.nodeName || "" ).toLowerCase(); + if ( nodeName === "input" ) { + fixDefaultChecked( elem ); + // Skip scripts, get other children + } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } +} + jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { var clone = elem.cloneNode(true), @@ -5526,7 +6280,10 @@ jQuery.extend({ // with an element if you are cloning the body and one of the // elements on the page has a name or id of "length" for ( i = 0; srcElements[i]; ++i ) { - cloneFixAttributes( srcElements[i], destElements[i] ); + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } } } @@ -5544,10 +6301,15 @@ jQuery.extend({ } } + srcElements = destElements = null; + // Return the cloned set return clone; -}, + }, + clean: function( elems, context, fragment, scripts ) { + var checkScriptType; + context = context || document; // !context.createElement fails in IE with an error but returns typeof 'object' @@ -5555,7 +6317,7 @@ jQuery.extend({ context = context.ownerDocument || context[0] && context[0].ownerDocument || document; } - var ret = []; + var ret = [], j; for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { if ( typeof elem === "number" ) { @@ -5567,54 +6329,76 @@ jQuery.extend({ } // Convert html string into DOM nodes - if ( typeof elem === "string" && !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - - } else if ( typeof elem === "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Trim whitespace, otherwise indexOf won't work as expected - var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(), - wrap = wrapMap[ tag ] || wrapMap._default, - depth = wrap[0], - div = context.createElement("div"); + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); + + // Trim whitespace, otherwise indexOf won't work as expected + var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(), + wrap = wrapMap[ tag ] || wrapMap._default, + depth = wrap[0], + div = context.createElement("div"); + + // Append wrapper element to unknown element safe doc fragment + if ( context === document ) { + // Use the fragment we've already created for this document + safeFragment.appendChild( div ); + } else { + // Use a fragment created with the owner document + createSafeFragment( context ).appendChild( div ); + } - // Go to html and back, then peel off extra wrappers - div.innerHTML = wrap[1] + elem + wrap[2]; + // Go to html and back, then peel off extra wrappers + div.innerHTML = wrap[1] + elem + wrap[2]; - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { - // String was a , *may* have spurious - var hasBody = rtbody.test(elem), - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : + // String was a
, *may* have spurious + var hasBody = rtbody.test(elem), + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : - // String was a bare or - wrap[1] === "
" && !hasBody ? - div.childNodes : - []; + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; - for ( var j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } } } - } + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + elem = div.childNodes; } + } - elem = div.childNodes; + // Resets defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + var len; + if ( !jQuery.support.appendChecked ) { + if ( elem[0] && typeof (len = elem.length) === "number" ) { + for ( j = 0; j < len; j++ ) { + findInputs( elem[j] ); + } + } else { + findInputs( elem ); + } } if ( elem.nodeType ) { @@ -5625,13 +6409,18 @@ jQuery.extend({ } if ( fragment ) { + checkScriptType = function( elem ) { + return !elem.type || rscriptType.test( elem.type ); + }; for ( i = 0; ret[i]; i++ ) { if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); } else { if ( ret[i].nodeType === 1 ) { - ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) ); + var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType ); + + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); } fragment.appendChild( ret[i] ); } @@ -5642,7 +6431,9 @@ jQuery.extend({ }, cleanData: function( elems ) { - var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special, + var data, id, + cache = jQuery.cache, + special = jQuery.event.special, deleteExpando = jQuery.support.deleteExpando; for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { @@ -5653,7 +6444,7 @@ jQuery.extend({ id = elem[ jQuery.expando ]; if ( id ) { - data = cache[ id ] && cache[ id ][ internalKey ]; + data = cache[ id ]; if ( data && data.events ) { for ( var type in data.events ) { @@ -5693,7 +6484,7 @@ function evalScript( i, elem ) { dataType: "script" }); } else { - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) ); } if ( elem.parentNode ) { @@ -5706,10 +6497,11 @@ function evalScript( i, elem ) { var ralpha = /alpha\([^)]*\)/i, ropacity = /opacity=([^)]*)/, - rdashAlpha = /-([a-z])/ig, - rupper = /([A-Z])/g, + // fixed for IE9, see #8346 + rupper = /([A-Z]|^ms)/g, rnumpx = /^-?\d+(?:px)?$/i, rnum = /^-?\d/, + rrelNum = /^([\-+])=([\-+.\de]+)/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssWidth = [ "Left", "Right" ], @@ -5717,11 +6509,7 @@ var ralpha = /alpha\([^)]*\)/i, curCSS, getComputedStyle, - currentStyle, - - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; + currentStyle; jQuery.fn.css = function( name, value ) { // Setting 'undefined' is a no-op @@ -5756,11 +6544,14 @@ jQuery.extend({ // Exclude the following css properties to add px cssNumber: { - "zIndex": true, + "fillOpacity": true, "fontWeight": true, + "lineHeight": true, "opacity": true, - "zoom": true, - "lineHeight": true + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true }, // Add in properties whose names you wish to fix before @@ -5778,20 +6569,29 @@ jQuery.extend({ } // Make sure that we're working with the right name - var ret, origName = jQuery.camelCase( name ), + var ret, type, origName = jQuery.camelCase( name ), style = elem.style, hooks = jQuery.cssHooks[ origName ]; name = jQuery.cssProps[ origName ] || origName; // Check if we're setting a value if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + // Make sure that NaN and null values aren't set. See: #7116 - if ( typeof value === "number" && isNaN( value ) || value == null ) { + if ( value == null || type === "number" && isNaN( value ) ) { return; } // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) { + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; } @@ -5816,11 +6616,17 @@ jQuery.extend({ }, css: function( elem, name, extra ) { + var ret, hooks; + // Make sure that we're working with the right name - var ret, origName = jQuery.camelCase( name ), - hooks = jQuery.cssHooks[ origName ]; + name = jQuery.camelCase( name ); + hooks = jQuery.cssHooks[ name ]; + name = jQuery.cssProps[ name ] || name; - name = jQuery.cssProps[ origName ] || origName; + // cssFloat needs a special treatment + if ( name === "cssFloat" ) { + name = "float"; + } // If a hook was provided get the computed value from there if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) { @@ -5828,7 +6634,7 @@ jQuery.extend({ // Otherwise, if a way to get the computed value exists, use that } else if ( curCSS ) { - return curCSS( elem, name, origName ); + return curCSS( elem, name ); } }, @@ -5848,10 +6654,6 @@ jQuery.extend({ for ( name in options ) { elem.style[ name ] = old[ name ]; } - }, - - camelCase: function( string ) { - return string.replace( rdashAlpha, fcamelCase ); } }); @@ -5865,44 +6667,21 @@ jQuery.each(["height", "width"], function( i, name ) { if ( computed ) { if ( elem.offsetWidth !== 0 ) { - val = getWH( elem, name, extra ); - + return getWH( elem, name, extra ); } else { jQuery.swap( elem, cssShow, function() { val = getWH( elem, name, extra ); }); } - if ( val <= 0 ) { - val = curCSS( elem, name, name ); - - if ( val === "0px" && currentStyle ) { - val = currentStyle( elem, name, name ); - } - - if ( val != null ) { - // Should return "auto" instead of 0, use 0 for - // temporary backwards-compat - return val === "" || val === "auto" ? "0px" : val; - } - } - - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - - // Should return "auto" instead of 0, use 0 for - // temporary backwards-compat - return val === "" || val === "auto" ? "0px" : val; - } - - return typeof val === "string" ? val : val + "px"; + return val; } }, set: function( elem, value ) { if ( rnumpx.test( value ) ) { // ignore negative width and height values #1599 - value = parseFloat(value); + value = parseFloat( value ); if ( value >= 0 ) { return value + "px"; @@ -5919,33 +6698,67 @@ if ( !jQuery.support.opacity ) { jQuery.cssHooks.opacity = { get: function( elem, computed ) { // IE uses filters for opacity - return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ? - (parseFloat(RegExp.$1) / 100) + "" : + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( parseFloat( RegExp.$1 ) / 100 ) + "" : computed ? "1" : ""; }, set: function( elem, value ) { - var style = elem.style; + var style = elem.style, + currentStyle = elem.currentStyle, + opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", + filter = currentStyle && currentStyle.filter || style.filter || ""; // IE has trouble with opacity if it does not have layout // Force it by setting the zoom level style.zoom = 1; - // Set the alpha filter to set the opacity - var opacity = jQuery.isNaN(value) ? - "" : - "alpha(opacity=" + value * 100 + ")", - filter = style.filter || ""; + // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 + if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) { + + // Setting style.filter to null, "" & " " still leave "filter:" in the cssText + // if "filter:" is present at all, clearType is disabled, we want to avoid this + // style.removeAttribute is IE Only, but so apparently is this code path... + style.removeAttribute( "filter" ); + + // if there there is no filter style applied in a css rule, we are done + if ( currentStyle && !currentStyle.filter ) { + return; + } + } - style.filter = ralpha.test(filter) ? - filter.replace(ralpha, opacity) : - style.filter + ' ' + opacity; + // otherwise, set new filter values + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; } }; } +jQuery(function() { + // This hook cannot be added until DOM ready because the support test + // for it is not run until after DOM ready + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + var ret; + jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + ret = curCSS( elem, "margin-right", "marginRight" ); + } else { + ret = elem.style.marginRight; + } + }); + return ret; + } + }; + } +}); + if ( document.defaultView && document.defaultView.getComputedStyle ) { - getComputedStyle = function( elem, newName, name ) { + getComputedStyle = function( elem, name ) { var ret, defaultView, computedStyle; name = name.replace( rupper, "-$1" ).toLowerCase(); @@ -5967,25 +6780,32 @@ if ( document.defaultView && document.defaultView.getComputedStyle ) { if ( document.documentElement.currentStyle ) { currentStyle = function( elem, name ) { - var left, + var left, rsLeft, uncomputed, ret = elem.currentStyle && elem.currentStyle[ name ], - rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ], style = elem.style; + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret === null && style && (uncomputed = style[ name ]) ) { + ret = uncomputed; + } + // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 // If we're not dealing with a regular pixel number // but a number that has a weird ending, we need to convert it to pixels if ( !rnumpx.test( ret ) && rnum.test( ret ) ) { + // Remember the original values left = style.left; + rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; // Put in the new values to get a computed value out if ( rsLeft ) { elem.runtimeStyle.left = elem.currentStyle.left; } - style.left = name === "fontSize" ? "1em" : (ret || 0); + style.left = name === "fontSize" ? "1em" : ( ret || 0 ); ret = style.pixelLeft + "px"; // Revert the changed values @@ -6002,27 +6822,50 @@ if ( document.documentElement.currentStyle ) { curCSS = getComputedStyle || currentStyle; function getWH( elem, name, extra ) { - var which = name === "width" ? cssWidth : cssHeight, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight; - if ( extra === "border" ) { - return val; - } + // Start with offset property + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + which = name === "width" ? cssWidth : cssHeight; - jQuery.each( which, function() { - if ( !extra ) { - val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0; + if ( val > 0 ) { + if ( extra !== "border" ) { + jQuery.each( which, function() { + if ( !extra ) { + val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; + } else { + val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; + } + }); } - if ( extra === "margin" ) { - val += parseFloat(jQuery.css( elem, "margin" + this )) || 0; + return val + "px"; + } - } else { - val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0; - } - }); + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ] || 0; + } + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Add padding, border, margin + if ( extra ) { + jQuery.each( which, function() { + val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; + if ( extra !== "padding" ) { + val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; + } + }); + } - return val; + return val + "px"; } if ( jQuery.expr && jQuery.expr.filters ) { @@ -6030,7 +6873,7 @@ if ( jQuery.expr && jQuery.expr.filters ) { var width = elem.offsetWidth, height = elem.offsetHeight; - return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none"); + return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none"); }; jQuery.expr.filters.visible = function( elem ) { @@ -6046,9 +6889,9 @@ var r20 = /%20/g, rCRLF = /\r?\n/g, rhash = /#.*$/, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /(?:^file|^widget|\-extension):$/, + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, rquery = /\?/, @@ -6056,11 +6899,7 @@ var r20 = /%20/g, rselectTextarea = /^(?:select|textarea)/i, rspacesAjax = /\s+/, rts = /([?&])_=[^&]*/, - rucHeaders = /(^|\-)([a-z])/g, - rucHeadersFunc = function( _, $1, $2 ) { - return $1 + $2.toUpperCase(); - }, - rurl = /^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/, // Keep a copy of the old load method _load = jQuery.fn.load, @@ -6087,12 +6926,15 @@ var r20 = /%20/g, ajaxLocation, // Document location segments - ajaxLocParts; + ajaxLocParts, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = ["*/"] + ["*"]; // #8138, IE may throw an exception when accessing -// a field from document.location if document.domain has been set +// a field from window.location if document.domain has been set try { - ajaxLocation = document.location.href; + ajaxLocation = location.href; } catch( e ) { // Use the href attribute of an A element // since IE will modify it given document.location @@ -6102,7 +6944,7 @@ try { } // Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ); +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -6124,7 +6966,7 @@ function addToPrefiltersOrTransports( structure ) { placeBefore; // For each dataType in the dataTypeExpression - for(; i < length; i++ ) { + for ( ; i < length; i++ ) { dataType = dataTypes[ i ]; // We control if we're asked to add before // any existing element @@ -6140,7 +6982,7 @@ function addToPrefiltersOrTransports( structure ) { }; } -//Base inspection function for prefilters and transports +// Base inspection function for prefilters and transports function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, dataType /* internal */, inspected /* internal */ ) { @@ -6155,7 +6997,7 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX executeOnly = ( structure === prefilters ), selection; - for(; i < length && ( executeOnly || !selection ); i++ ) { + for ( ; i < length && ( executeOnly || !selection ); i++ ) { selection = list[ i ]( options, originalOptions, jqXHR ); // If we got redirected to another dataType // we try there if executing only and not done already @@ -6180,6 +7022,22 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX return selection; } +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + jQuery.fn.extend({ load: function( url, params, callback ) { if ( typeof url !== "string" && _load ) { @@ -6289,7 +7147,7 @@ jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".sp jQuery.fn[ o ] = function( f ){ return this.bind( o, f ); }; -} ); +}); jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { @@ -6308,7 +7166,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { dataType: type }); }; -} ); +}); jQuery.extend({ @@ -6323,23 +7181,16 @@ jQuery.extend({ // Creates a full fledged settings object into target // with both ajaxSettings and settings fields. // If target is omitted, writes into ajaxSettings. - ajaxSetup: function ( target, settings ) { - if ( !settings ) { - // Only one parameter, we extend ajaxSettings - settings = target; - target = jQuery.extend( true, jQuery.ajaxSettings, settings ); + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); } else { - // target was provided, we extend into it - jQuery.extend( true, target, jQuery.ajaxSettings, settings ); - } - // Flatten fields we don't want deep extended - for( var field in { context: 1, url: 1 } ) { - if ( field in settings ) { - target[ field ] = settings[ field ]; - } else if( field in jQuery.ajaxSettings ) { - target[ field ] = jQuery.ajaxSettings[ field ]; - } + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; } + ajaxExtend( target, settings ); return target; }, @@ -6360,7 +7211,6 @@ jQuery.extend({ cache: null, traditional: false, headers: {}, - crossDomain: null, */ accepts: { @@ -6368,7 +7218,7 @@ jQuery.extend({ html: "text/html", text: "text/plain", json: "application/json, text/javascript", - "*": "*/*" + "*": allTypes }, contents: { @@ -6398,6 +7248,15 @@ jQuery.extend({ // Parse text as xml "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true } }, @@ -6428,13 +7287,14 @@ jQuery.extend({ jQuery( callbackContext ) : jQuery.event, // Deferreds deferred = jQuery.Deferred(), - completeDeferred = jQuery._Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), // Status-dependent callbacks statusCode = s.statusCode || {}, // ifModified key ifModifiedKey, // Headers (they are sent all at once) requestHeaders = {}, + requestHeadersNames = {}, // Response headers responseHeadersString, responseHeaders, @@ -6458,7 +7318,9 @@ jQuery.extend({ // Caches the header setRequestHeader: function( name, value ) { if ( !state ) { - requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value; + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; } return this; }, @@ -6505,7 +7367,7 @@ jQuery.extend({ // Callback for when everything is done // It is defined here because jslint complains if it is declared // at the end of the function (which would be more logical and readable) - function done( status, statusText, responses, headers ) { + function done( status, nativeStatusText, responses, headers ) { // Called once if ( state === 2 ) { @@ -6528,11 +7390,12 @@ jQuery.extend({ responseHeadersString = headers || ""; // Set readyState - jqXHR.readyState = status ? 4 : 0; + jqXHR.readyState = status > 0 ? 4 : 0; var isSuccess, success, error, + statusText = nativeStatusText, response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined, lastModified, etag; @@ -6574,7 +7437,7 @@ jQuery.extend({ // We extract error from statusText // then normalize statusText and status for non-aborts error = statusText; - if( !statusText || status ) { + if ( !statusText || status ) { statusText = "error"; if ( status < 0 ) { status = 0; @@ -6584,7 +7447,7 @@ jQuery.extend({ // Set data for the fake xhr object jqXHR.status = status; - jqXHR.statusText = statusText; + jqXHR.statusText = "" + ( nativeStatusText || statusText ); // Success/Error if ( isSuccess ) { @@ -6603,10 +7466,10 @@ jQuery.extend({ } // Complete - completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] ); + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] ); + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); // Handle the global AJAX counter if ( !( --jQuery.active ) ) { jQuery.event.trigger( "ajaxStop" ); @@ -6618,14 +7481,14 @@ jQuery.extend({ deferred.promise( jqXHR ); jqXHR.success = jqXHR.done; jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.done; + jqXHR.complete = completeDeferred.add; // Status-dependent callbacks jqXHR.statusCode = function( map ) { if ( map ) { var tmp; if ( state < 2 ) { - for( tmp in map ) { + for ( tmp in map ) { statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; } } else { @@ -6645,7 +7508,7 @@ jQuery.extend({ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax ); // Determine if a cross-domain request is in order - if ( !s.crossDomain ) { + if ( s.crossDomain == null ) { parts = rurl.exec( s.url.toLowerCase() ); s.crossDomain = !!( parts && ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || @@ -6687,6 +7550,8 @@ jQuery.extend({ // If data is available, append data to url if ( s.data ) { s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + // #9682: remove data so that it's not used in an eventual retry + delete s.data; } // Get ifModifiedKey before adding the anti-cache parameter @@ -6700,30 +7565,33 @@ jQuery.extend({ ret = s.url.replace( rts, "$1_=" + ts ); // if nothing was replaced, add timestamp to the end - s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); + s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); } } // Set the correct header, if data is being sent if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - requestHeaders[ "Content-Type" ] = s.contentType; + jqXHR.setRequestHeader( "Content-Type", s.contentType ); } // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { ifModifiedKey = ifModifiedKey || s.url; if ( jQuery.lastModified[ ifModifiedKey ] ) { - requestHeaders[ "If-Modified-Since" ] = jQuery.lastModified[ ifModifiedKey ]; + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); } if ( jQuery.etag[ ifModifiedKey ] ) { - requestHeaders[ "If-None-Match" ] = jQuery.etag[ ifModifiedKey ]; + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); } } // Set the Accepts header for the server, depending on the dataType - requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : - s.accepts[ "*" ]; + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); // Check for headers option for ( i in s.headers ) { @@ -6767,7 +7635,7 @@ jQuery.extend({ transport.send( requestHeaders, done ); } catch (e) { // Propagate exception as error if not done - if ( status < 2 ) { + if ( state < 2 ) { done( -1, e ); // Simply rethrow otherwise } else { @@ -6799,7 +7667,7 @@ jQuery.extend({ // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); - } ); + }); } else { // If traditional, encode the "old" way (the way 1.3.2 or older @@ -6815,7 +7683,7 @@ jQuery.extend({ }); function buildParams( prefix, obj, traditional, add ) { - if ( jQuery.isArray( obj ) && obj.length ) { + if ( jQuery.isArray( obj ) ) { // Serialize array item. jQuery.each( obj, function( i, v ) { if ( traditional || rbracket.test( prefix ) ) { @@ -6835,16 +7703,9 @@ function buildParams( prefix, obj, traditional, add ) { }); } else if ( !traditional && obj != null && typeof obj === "object" ) { - // If we see an array here, it is empty and should be treated as an empty - // object - if ( jQuery.isArray( obj ) || jQuery.isEmptyObject( obj ) ) { - add( prefix, "" ); - // Serialize object item. - } else { - for ( var name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } + for ( var name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); } } else { @@ -6882,7 +7743,7 @@ function ajaxHandleResponses( s, jqXHR, responses ) { firstDataType; // Fill responseXXX fields - for( type in responseFields ) { + for ( type in responseFields ) { if ( type in responses ) { jqXHR[ responseFields[type] ] = responses[ type ]; } @@ -6961,13 +7822,13 @@ function ajaxConvert( s, response ) { conv2; // For each dataType in the chain - for( i = 1; i < length; i++ ) { + for ( i = 1; i < length; i++ ) { // Create converters map // with lowercased keys if ( i === 1 ) { - for( key in s.converters ) { - if( typeof key === "string" ) { + for ( key in s.converters ) { + if ( typeof key === "string" ) { converters[ key.toLowerCase() ] = s.converters[ key ]; } } @@ -6978,7 +7839,7 @@ function ajaxConvert( s, response ) { current = dataTypes[ i ]; // If current is auto dataType, update it to prev - if( current === "*" ) { + if ( current === "*" ) { current = prev; // If no auto and dataTypes are actually different } else if ( prev !== "*" && prev !== current ) { @@ -6990,7 +7851,7 @@ function ajaxConvert( s, response ) { // If there is no direct converter, search transitively if ( !conv ) { conv2 = undefined; - for( conv1 in converters ) { + for ( conv1 in converters ) { tmp = conv1.split( " " ); if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) { conv2 = converters[ tmp[1] + " " + current ]; @@ -7024,7 +7885,7 @@ function ajaxConvert( s, response ) { var jsc = jQuery.now(), - jsre = /(\=)\?(&|$)|()\?\?()/i; + jsre = /(\=)\?(&|$)|\?\?/i; // Default jsonp settings jQuery.ajaxSetup({ @@ -7037,13 +7898,12 @@ jQuery.ajaxSetup({ // Detect, normalize options and install callbacks for jsonp requests jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - var dataIsString = ( typeof s.data === "string" ); + var inspectData = s.contentType === "application/x-www-form-urlencoded" && + ( typeof s.data === "string" ); if ( s.dataTypes[ 0 ] === "jsonp" || - originalSettings.jsonpCallback || - originalSettings.jsonp != null || s.jsonp !== false && ( jsre.test( s.url ) || - dataIsString && jsre.test( s.data ) ) ) { + inspectData && jsre.test( s.data ) ) ) { var responseContainer, jsonpCallback = s.jsonpCallback = @@ -7051,20 +7911,12 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { previous = window[ jsonpCallback ], url = s.url, data = s.data, - replace = "$1" + jsonpCallback + "$2", - cleanUp = function() { - // Set callback back to previous value - window[ jsonpCallback ] = previous; - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( previous ) ) { - window[ jsonpCallback ]( responseContainer[ 0 ] ); - } - }; + replace = "$1" + jsonpCallback + "$2"; if ( s.jsonp !== false ) { url = url.replace( jsre, replace ); if ( s.url === url ) { - if ( dataIsString ) { + if ( inspectData ) { data = data.replace( jsre, replace ); } if ( s.data === data ) { @@ -7082,8 +7934,15 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { responseContainer = [ response ]; }; - // Install cleanUp function - jqXHR.then( cleanUp, cleanUp ); + // Clean-up function + jqXHR.always(function() { + // Set callback back to previous value + window[ jsonpCallback ] = previous; + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( previous ) ) { + window[ jsonpCallback ]( responseContainer[ 0 ] ); + } + }); // Use data converter to retrieve json after script execution s.converters["script json"] = function() { @@ -7099,7 +7958,7 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { // Delegate to script return "script"; } -} ); +}); @@ -7129,7 +7988,7 @@ jQuery.ajaxPrefilter( "script", function( s ) { s.type = "GET"; s.global = false; } -} ); +}); // Bind script tag hack transport jQuery.ajaxTransport( "script", function(s) { @@ -7157,7 +8016,7 @@ jQuery.ajaxTransport( "script", function(s) { // Attach handlers for all browsers script.onload = script.onreadystatechange = function( _, isAbort ) { - if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) { + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { // Handle memory leak in IE script.onload = script.onreadystatechange = null; @@ -7188,27 +8047,20 @@ jQuery.ajaxTransport( "script", function(s) { } }; } -} ); - - +}); -var // #5280: next active xhr id and list of active xhrs' callbacks - xhrId = jQuery.now(), - xhrCallbacks, - // XHR used to determine supports properties - testXHR; -// #5280: Internet Explorer will keep connections alive if we don't abort on unload -function xhrOnUnloadAbort() { - jQuery( window ).unload(function() { +var // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { // Abort all pending requests for ( var key in xhrCallbacks ) { xhrCallbacks[ key ]( 0, 1 ); } - }); -} + } : false, + xhrId = 0, + xhrCallbacks; // Functions to create xhrs function createStandardXHR() { @@ -7238,15 +8090,13 @@ jQuery.ajaxSettings.xhr = window.ActiveXObject ? // For all other browsers, use the standard XMLHttpRequest object createStandardXHR; -// Test if we can create an xhr object -testXHR = jQuery.ajaxSettings.xhr(); -jQuery.support.ajax = !!testXHR; - -// Does this browser support crossDomain XHR requests -jQuery.support.cors = testXHR && ( "withCredentials" in testXHR ); - -// No need for the temporary xhr anymore -testXHR = undefined; +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); // Create transport if the browser can provide an xhr if ( jQuery.support.ajax ) { @@ -7285,11 +8135,12 @@ if ( jQuery.support.ajax ) { xhr.overrideMimeType( s.mimeType ); } - // Requested-With header - // Not set for crossDomain requests with no content - // (see why at http://trac.dojotoolkit.org/ticket/9486) - // Won't change header if already provided - if ( !( s.crossDomain && !s.hasContent ) && !headers["X-Requested-With"] ) { + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { headers[ "X-Requested-With" ] = "XMLHttpRequest"; } @@ -7328,7 +8179,9 @@ if ( jQuery.support.ajax ) { // Do not keep as active anymore if ( handle ) { xhr.onreadystatechange = jQuery.noop; - delete xhrCallbacks[ handle ]; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } } // If it's an abort @@ -7389,15 +8242,18 @@ if ( jQuery.support.ajax ) { if ( !s.async || xhr.readyState === 4 ) { callback(); } else { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - xhrOnUnloadAbort(); + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; } - // Add to list of active xhrs callbacks - handle = xhrId++; - xhr.onreadystatechange = xhrCallbacks[ handle ] = callback; + xhr.onreadystatechange = callback; } }, @@ -7415,6 +8271,7 @@ if ( jQuery.support.ajax ) { var elemdisplay = {}, + iframe, iframeDoc, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, timerId, @@ -7425,42 +8282,49 @@ var elemdisplay = {}, [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], // opacity animations [ "opacity" ] - ]; + ], + fxNow; jQuery.fn.extend({ show: function( speed, easing, callback ) { var elem, display; if ( speed || speed === 0 ) { - return this.animate( genFx("show", 3), speed, easing, callback); + return this.animate( genFx("show", 3), speed, easing, callback ); } else { for ( var i = 0, j = this.length; i < j; i++ ) { - elem = this[i]; - display = elem.style.display; + elem = this[ i ]; - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { - display = elem.style.display = ""; - } + if ( elem.style ) { + display = elem.style.display; + + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { + display = elem.style.display = ""; + } - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { - jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( display === "" && jQuery.css(elem, "display") === "none" ) { + jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) ); + } } } // Set the display of most of the elements in a second loop // to avoid the constant reflow for ( i = 0; i < j; i++ ) { - elem = this[i]; - display = elem.style.display; + elem = this[ i ]; - if ( display === "" || display === "none" ) { - elem.style.display = jQuery._data(elem, "olddisplay") || ""; + if ( elem.style ) { + display = elem.style.display; + + if ( display === "" || display === "none" ) { + elem.style.display = jQuery._data( elem, "olddisplay" ) || ""; + } } } @@ -7473,18 +8337,27 @@ jQuery.fn.extend({ return this.animate( genFx("hide", 3), speed, easing, callback); } else { - for ( var i = 0, j = this.length; i < j; i++ ) { - var display = jQuery.css( this[i], "display" ); + var elem, display, + i = 0, + j = this.length; + + for ( ; i < j; i++ ) { + elem = this[i]; + if ( elem.style ) { + display = jQuery.css( elem, "display" ); - if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) { - jQuery._data( this[i], "olddisplay", display ); + if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) { + jQuery._data( elem, "olddisplay", display ); + } } } // Set the display of the elements in a second loop // to avoid the constant reflow for ( i = 0; i < j; i++ ) { - this[i].style.display = "none"; + if ( this[i].style ) { + this[i].style.display = "none"; + } } return this; @@ -7519,35 +8392,57 @@ jQuery.fn.extend({ }, animate: function( prop, speed, easing, callback ) { - var optall = jQuery.speed(speed, easing, callback); + var optall = jQuery.speed( speed, easing, callback ); if ( jQuery.isEmptyObject( prop ) ) { - return this.each( optall.complete ); + return this.each( optall.complete, [ false ] ); } - return this[ optall.queue === false ? "each" : "queue" ](function() { + // Do not change referenced properties as per-property easing will be lost + prop = jQuery.extend( {}, prop ); + + function doAnimation() { // XXX 'this' does not always have a nodeName when running the // test suite - var opt = jQuery.extend({}, optall), p, + if ( optall.queue === false ) { + jQuery._mark( this ); + } + + var opt = jQuery.extend( {}, optall ), isElement = this.nodeType === 1, hidden = isElement && jQuery(this).is(":hidden"), - self = this; + name, val, p, e, + parts, start, end, unit, + method; + + // will store per property easing and be used to determine when an animation is complete + opt.animatedProperties = {}; for ( p in prop ) { - var name = jQuery.camelCase( p ); + // property name normalization + name = jQuery.camelCase( p ); if ( p !== name ) { prop[ name ] = prop[ p ]; delete prop[ p ]; - p = name; } - if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) { - return opt.complete.call(this); + val = prop[ name ]; + + // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) + if ( jQuery.isArray( val ) ) { + opt.animatedProperties[ name ] = val[ 1 ]; + val = prop[ name ] = val[ 0 ]; + } else { + opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; + } + + if ( val === "hide" && hidden || val === "show" && !hidden ) { + return opt.complete.call( this ); } - if ( isElement && ( p === "height" || p === "width" ) ) { + if ( isElement && ( name === "height" || name === "width" ) ) { // Make sure that nothing sneaks out // Record all 3 overflow attributes because IE does not // change the overflow attribute when overflowX and @@ -7555,66 +8450,60 @@ jQuery.fn.extend({ opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ]; // Set display property to inline-block for height/width - // animations on inline elements that are having width/height - // animated + // animations on inline elements that are having width/height animated if ( jQuery.css( this, "display" ) === "inline" && jQuery.css( this, "float" ) === "none" ) { - if ( !jQuery.support.inlineBlockNeedsLayout ) { + + // inline-level elements accept inline-block; + // block-level elements need to be inline with layout + if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) { this.style.display = "inline-block"; } else { - var display = defaultDisplay(this.nodeName); - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( display === "inline" ) { - this.style.display = "inline-block"; - - } else { - this.style.display = "inline"; - this.style.zoom = 1; - } + this.style.zoom = 1; } } } - - if ( jQuery.isArray( prop[p] ) ) { - // Create (if needed) and add to specialEasing - (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1]; - prop[p] = prop[p][0]; - } } if ( opt.overflow != null ) { this.style.overflow = "hidden"; } - opt.curAnim = jQuery.extend({}, prop); + for ( p in prop ) { + e = new jQuery.fx( this, opt, p ); + val = prop[ p ]; - jQuery.each( prop, function( name, val ) { - var e = new jQuery.fx( self, opt, name ); + if ( rfxtypes.test( val ) ) { - if ( rfxtypes.test(val) ) { - e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop ); + // Tracks whether to show or hide based on private + // data attached to the element + method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 ); + if ( method ) { + jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" ); + e[ method ](); + } else { + e[ val ](); + } } else { - var parts = rfxnum.exec(val), - start = e.cur(); + parts = rfxnum.exec( val ); + start = e.cur(); if ( parts ) { - var end = parseFloat( parts[2] ), - unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" ); + end = parseFloat( parts[2] ); + unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" ); // We need to compute starting value if ( unit !== "px" ) { - jQuery.style( self, name, (end || 1) + unit); - start = ((end || 1) / e.cur()) * start; - jQuery.style( self, name, start + unit); + jQuery.style( this, p, (end || 1) + unit); + start = ( (end || 1) / e.cur() ) * start; + jQuery.style( this, p, start + unit); } // If a +=/-= token was provided, we're doing a relative animation if ( parts[1] ) { - end = ((parts[1] === "-=" ? -1 : 1) * end) + start; + end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start; } e.custom( start, end, unit ); @@ -7623,48 +8512,94 @@ jQuery.fn.extend({ e.custom( start, val, "" ); } } - }); + } // For JS strict compliance return true; - }); - }, + } - stop: function( clearQueue, gotoEnd ) { - var timers = jQuery.timers; + return optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, - if ( clearQueue ) { - this.queue([]); + stop: function( type, clearQueue, gotoEnd ) { + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); } - this.each(function() { - // go in reverse order so anything added to the queue during the loop is ignored - for ( var i = timers.length - 1; i >= 0; i-- ) { - if ( timers[i].elem === this ) { - if (gotoEnd) { - // force the next step to be the last - timers[i](true); - } + return this.each(function() { + var i, + hadTimers = false, + timers = jQuery.timers, + data = jQuery._data( this ); + + // clear marker counters if we know they won't be + if ( !gotoEnd ) { + jQuery._unmark( true, this ); + } + + function stopQueue( elem, data, i ) { + var hooks = data[ i ]; + jQuery.removeData( elem, i, true ); + hooks.stop( gotoEnd ); + } - timers.splice(i, 1); + if ( type == null ) { + for ( i in data ) { + if ( data[ i ].stop && i.indexOf(".run") === i.length - 4 ) { + stopQueue( this, data, i ); + } } + } else if ( data[ i = type + ".run" ] && data[ i ].stop ){ + stopQueue( this, data, i ); } - }); - // start the next in the queue if the last step wasn't forced - if ( !gotoEnd ) { - this.dequeue(); - } + for ( i = timers.length; i--; ) { + if ( timers[ i ].elem === this && (type == null || timers[ i ].queue === type) ) { + if ( gotoEnd ) { - return this; + // force the next step to be the last + timers[ i ]( true ); + } else { + timers[ i ].saveState(); + } + hadTimers = true; + timers.splice( i, 1 ); + } + } + + // start the next in the queue if the last step wasn't forced + // timers currently will call their complete callbacks, which will dequeue + // but only if they were gotoEnd + if ( !( gotoEnd && hadTimers ) ) { + jQuery.dequeue( this, type ); + } + }); } }); +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout( clearFxNow, 0 ); + return ( fxNow = jQuery.now() ); +} + +function clearFxNow() { + fxNow = undefined; +} + +// Generate parameters to create a standard animation function genFx( type, num ) { var obj = {}; - jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() { + jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() { obj[ this ] = type; }); @@ -7673,9 +8608,9 @@ function genFx( type, num ) { // Generate shortcuts for custom animations jQuery.each({ - slideDown: genFx("show", 1), - slideUp: genFx("hide", 1), - slideToggle: genFx("toggle", 1), + slideDown: genFx( "show", 1 ), + slideUp: genFx( "hide", 1 ), + slideToggle: genFx( "toggle", 1 ), fadeIn: { opacity: "show" }, fadeOut: { opacity: "hide" }, fadeToggle: { opacity: "toggle" } @@ -7687,25 +8622,34 @@ jQuery.each({ jQuery.extend({ speed: function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || jQuery.isFunction( speed ) && speed, duration: speed, - easing: fn && easing || easing && !jQuery.isFunction(easing) && easing + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default; + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + + // normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } // Queueing opt.old = opt.complete; - opt.complete = function() { - if ( opt.queue !== false ) { - jQuery(this).dequeue(); - } + + opt.complete = function( noUnmark ) { if ( jQuery.isFunction( opt.old ) ) { opt.old.call( this ); } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } else if ( noUnmark !== false ) { + jQuery._unmark( this ); + } }; return opt; @@ -7716,7 +8660,7 @@ jQuery.extend({ return firstNum + diff * p; }, swing: function( p, n, firstNum, diff ) { - return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum; + return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum; } }, @@ -7727,9 +8671,7 @@ jQuery.extend({ this.elem = elem; this.prop = prop; - if ( !options.orig ) { - options.orig = {}; - } + options.orig = options.orig || {}; } }); @@ -7741,12 +8683,12 @@ jQuery.fx.prototype = { this.options.step.call( this.elem, this.now, this ); } - (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); + ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this ); }, // Get the current size cur: function() { - if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) { + if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) { return this.elem[ this.prop ]; } @@ -7763,34 +8705,45 @@ jQuery.fx.prototype = { var self = this, fx = jQuery.fx; - this.startTime = jQuery.now(); - this.start = from; + this.startTime = fxNow || createFxNow(); this.end = to; - this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); - this.now = this.start; + this.now = this.start = from; this.pos = this.state = 0; + this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); function t( gotoEnd ) { - return self.step(gotoEnd); + return self.step( gotoEnd ); } + t.queue = this.options.queue; t.elem = this.elem; + t.saveState = function() { + if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) { + jQuery._data( self.elem, "fxshow" + self.prop, self.start ); + } + }; if ( t() && jQuery.timers.push(t) && !timerId ) { - timerId = setInterval(fx.tick, fx.interval); + timerId = setInterval( fx.tick, fx.interval ); } }, // Simple 'show' function show: function() { + var dataShow = jQuery._data( this.elem, "fxshow" + this.prop ); + // Remember where we started, so that we can go back to it later - this.options.orig[this.prop] = jQuery.style( this.elem, this.prop ); + this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop ); this.options.show = true; // Begin the animation - // Make sure that we start at a small width/height to avoid any - // flash of content - this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur()); + // Make sure that we start at a small width/height to avoid any flash of content + if ( dataShow !== undefined ) { + // This show is picking up where a previous hide or show left off + this.custom( this.cur(), dataShow ); + } else { + this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() ); + } // Start by showing the element jQuery( this.elem ).show(); @@ -7799,69 +8752,84 @@ jQuery.fx.prototype = { // Simple 'hide' function hide: function() { // Remember where we started, so that we can go back to it later - this.options.orig[this.prop] = jQuery.style( this.elem, this.prop ); + this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop ); this.options.hide = true; // Begin the animation - this.custom(this.cur(), 0); + this.custom( this.cur(), 0 ); }, // Each step of an animation step: function( gotoEnd ) { - var t = jQuery.now(), done = true; + var p, n, complete, + t = fxNow || createFxNow(), + done = true, + elem = this.elem, + options = this.options; - if ( gotoEnd || t >= this.options.duration + this.startTime ) { + if ( gotoEnd || t >= options.duration + this.startTime ) { this.now = this.end; this.pos = this.state = 1; this.update(); - this.options.curAnim[ this.prop ] = true; + options.animatedProperties[ this.prop ] = true; - for ( var i in this.options.curAnim ) { - if ( this.options.curAnim[i] !== true ) { + for ( p in options.animatedProperties ) { + if ( options.animatedProperties[ p ] !== true ) { done = false; } } if ( done ) { // Reset the overflow - if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { - var elem = this.elem, - options = this.options; + if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { - jQuery.each( [ "", "X", "Y" ], function (index, value) { - elem.style[ "overflow" + value ] = options.overflow[index]; - } ); + jQuery.each( [ "", "X", "Y" ], function( index, value ) { + elem.style[ "overflow" + value ] = options.overflow[ index ]; + }); } // Hide the element if the "hide" operation was done - if ( this.options.hide ) { - jQuery(this.elem).hide(); + if ( options.hide ) { + jQuery( elem ).hide(); } // Reset the properties, if the item has been hidden or shown - if ( this.options.hide || this.options.show ) { - for ( var p in this.options.curAnim ) { - jQuery.style( this.elem, p, this.options.orig[p] ); + if ( options.hide || options.show ) { + for ( p in options.animatedProperties ) { + jQuery.style( elem, p, options.orig[ p ] ); + jQuery.removeData( elem, "fxshow" + p, true ); + // Toggle data is no longer needed + jQuery.removeData( elem, "toggle" + p, true ); } } // Execute the complete function - this.options.complete.call( this.elem ); + // in the event that the complete function throws an exception + // we must ensure it won't be called twice. #5684 + + complete = options.complete; + if ( complete ) { + + options.complete = false; + complete.call( elem ); + } } return false; } else { - var n = t - this.startTime; - this.state = n / this.options.duration; - - // Perform the easing function, defaults to swing - var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop]; - var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear"); - this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration); - this.now = this.start + ((this.end - this.start) * this.pos); + // classical easing cannot be used with an Infinity duration + if ( options.duration == Infinity ) { + this.now = t; + } else { + n = t - this.startTime; + this.state = n / options.duration; + // Perform the easing function, defaults to swing + this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration ); + this.now = this.start + ( (this.end - this.start) * this.pos ); + } // Perform the next step of the animation this.update(); } @@ -7872,11 +8840,15 @@ jQuery.fx.prototype = { jQuery.extend( jQuery.fx, { tick: function() { - var timers = jQuery.timers; + var timer, + timers = jQuery.timers, + i = 0; - for ( var i = 0; i < timers.length; i++ ) { - if ( !timers[i]() ) { - timers.splice(i--, 1); + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + // Checks the timer has not already been removed + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); } } @@ -7906,7 +8878,7 @@ jQuery.extend( jQuery.fx, { _default: function( fx ) { if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) { - fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit; + fx.elem.style[ fx.prop ] = fx.now + fx.unit; } else { fx.elem[ fx.prop ] = fx.now; } @@ -7914,6 +8886,14 @@ jQuery.extend( jQuery.fx, { } }); +// Adds width/height step functions +// Do not set anything below 0 +jQuery.each([ "width", "height" ], function( i, prop ) { + jQuery.fx.step[ prop ] = function( fx ) { + jQuery.style( fx.elem, prop, Math.max(0, fx.now) ); + }; +}); + if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.animated = function( elem ) { return jQuery.grep(jQuery.timers, function( fn ) { @@ -7922,17 +8902,45 @@ if ( jQuery.expr && jQuery.expr.filters ) { }; } +// Try to restore the default display value of an element function defaultDisplay( nodeName ) { + if ( !elemdisplay[ nodeName ] ) { - var elem = jQuery("<" + nodeName + ">").appendTo("body"), - display = elem.css("display"); + var body = document.body, + elem = jQuery( "<" + nodeName + ">" ).appendTo( body ), + display = elem.css( "display" ); elem.remove(); + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe if ( display === "none" || display === "" ) { - display = "block"; + // No iframe to use yet, so create it + if ( !iframe ) { + iframe = document.createElement( "iframe" ); + iframe.frameBorder = iframe.width = iframe.height = 0; + } + + body.appendChild( iframe ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "" : "" ) + "" ); + iframeDoc.close(); + } + + elem = iframeDoc.createElement( nodeName ); + + iframeDoc.body.appendChild( elem ); + + display = jQuery.css( elem, "display" ); + body.removeChild( iframe ); } + // Store the correct default display elemdisplay[ nodeName ] = display; } @@ -7979,8 +8987,8 @@ if ( "getBoundingClientRect" in document.documentElement ) { win = getWindow(doc), clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, - scrollTop = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ), - scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft), + scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop, + scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft, top = box.top + scrollTop - clientTop, left = box.left + scrollLeft - clientLeft; @@ -8005,8 +9013,6 @@ if ( "getBoundingClientRect" in document.documentElement ) { return jQuery.offset.bodyOffset( elem ); } - jQuery.offset.initialize(); - var computedStyle, offsetParent = elem.offsetParent, prevOffsetParent = elem, @@ -8019,7 +9025,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { left = elem.offsetLeft; while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) { - if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { + if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) { break; } @@ -8031,7 +9037,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { top += elem.offsetTop; left += elem.offsetLeft; - if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) { + if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) { top += parseFloat( computedStyle.borderTopWidth ) || 0; left += parseFloat( computedStyle.borderLeftWidth ) || 0; } @@ -8040,7 +9046,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { offsetParent = elem.offsetParent; } - if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) { + if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) { top += parseFloat( computedStyle.borderTopWidth ) || 0; left += parseFloat( computedStyle.borderLeftWidth ) || 0; } @@ -8053,7 +9059,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { left += body.offsetLeft; } - if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { + if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) { top += Math.max( docElem.scrollTop, body.scrollTop ); left += Math.max( docElem.scrollLeft, body.scrollLeft ); } @@ -8063,47 +9069,12 @@ if ( "getBoundingClientRect" in document.documentElement ) { } jQuery.offset = { - initialize: function() { - var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0, - html = "
"; - - jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } ); - - container.innerHTML = html; - body.insertBefore( container, body.firstChild ); - innerDiv = container.firstChild; - checkDiv = innerDiv.firstChild; - td = innerDiv.nextSibling.firstChild.firstChild; - - this.doesNotAddBorder = (checkDiv.offsetTop !== 5); - this.doesAddBorderForTableAndCells = (td.offsetTop === 5); - - checkDiv.style.position = "fixed"; - checkDiv.style.top = "20px"; - - // safari subtracts parent border width here which is 5px - this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15); - checkDiv.style.position = checkDiv.style.top = ""; - - innerDiv.style.overflow = "hidden"; - innerDiv.style.position = "relative"; - - this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5); - - this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop); - - body.removeChild( container ); - body = container = innerDiv = checkDiv = table = td = null; - jQuery.offset.initialize = jQuery.noop; - }, bodyOffset: function( body ) { var top = body.offsetTop, left = body.offsetLeft; - jQuery.offset.initialize(); - - if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) { + if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { top += parseFloat( jQuery.css(body, "marginTop") ) || 0; left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; } @@ -8123,26 +9094,28 @@ jQuery.offset = { curOffset = curElem.offset(), curCSSTop = jQuery.css( elem, "top" ), curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1), + calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, props = {}, curPosition = {}, curTop, curLeft; - // need to be able to calculate position if either top or left is auto and position is absolute + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed if ( calculatePosition ) { curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; } - curTop = calculatePosition ? curPosition.top : parseInt( curCSSTop, 10 ) || 0; - curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0; - if ( jQuery.isFunction( options ) ) { options = options.call( elem, i, curOffset ); } - if (options.top != null) { - props.top = (options.top - curOffset.top) + curTop; + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; } - if (options.left != null) { - props.left = (options.left - curOffset.left) + curLeft; + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; } if ( "using" in options ) { @@ -8155,6 +9128,7 @@ jQuery.offset = { jQuery.fn.extend({ + position: function() { if ( !this[0] ) { return null; @@ -8202,29 +9176,16 @@ jQuery.fn.extend({ jQuery.each( ["Left", "Top"], function( i, name ) { var method = "scroll" + name; - jQuery.fn[ method ] = function(val) { - var elem = this[0], win; - - if ( !elem ) { - return null; - } + jQuery.fn[ method ] = function( val ) { + var elem, win; - if ( val !== undefined ) { - // Set the scroll offset - return this.each(function() { - win = getWindow( this ); + if ( val === undefined ) { + elem = this[ 0 ]; - if ( win ) { - win.scrollTo( - !i ? val : jQuery(win).scrollLeft(), - i ? val : jQuery(win).scrollTop() - ); + if ( !elem ) { + return null; + } - } else { - this[ method ] = val; - } - }); - } else { win = getWindow( elem ); // Return the scroll offset @@ -8233,6 +9194,21 @@ jQuery.each( ["Left", "Top"], function( i, name ) { win.document.body[ method ] : elem[ method ]; } + + // Set the scroll offset + return this.each(function() { + win = getWindow( this ); + + if ( win ) { + win.scrollTo( + !i ? val : jQuery( win ).scrollLeft(), + i ? val : jQuery( win ).scrollTop() + ); + + } else { + this[ method ] = val; + } + }); }; }); @@ -8247,22 +9223,28 @@ function getWindow( elem ) { -// Create innerHeight, innerWidth, outerHeight and outerWidth methods +// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods jQuery.each([ "Height", "Width" ], function( i, name ) { var type = name.toLowerCase(); // innerHeight and innerWidth - jQuery.fn["inner" + name] = function() { - return this[0] ? - parseFloat( jQuery.css( this[0], type, "padding" ) ) : + jQuery.fn[ "inner" + name ] = function() { + var elem = this[0]; + return elem ? + elem.style ? + parseFloat( jQuery.css( elem, type, "padding" ) ) : + this[ type ]() : null; }; // outerHeight and outerWidth - jQuery.fn["outer" + name] = function( margin ) { - return this[0] ? - parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) : + jQuery.fn[ "outer" + name ] = function( margin ) { + var elem = this[0]; + return elem ? + elem.style ? + parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) : + this[ type ]() : null; }; @@ -8283,9 +9265,10 @@ jQuery.each([ "Height", "Width" ], function( i, name ) { if ( jQuery.isWindow( elem ) ) { // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat - var docElemProp = elem.document.documentElement[ "client" + name ]; + var docElemProp = elem.document.documentElement[ "client" + name ], + body = elem.document.body; return elem.document.compatMode === "CSS1Compat" && docElemProp || - elem.document.body[ "client" + name ] || docElemProp; + body && body[ "client" + name ] || docElemProp; // Get document width or height } else if ( elem.nodeType === 9 ) { @@ -8301,7 +9284,7 @@ jQuery.each([ "Height", "Width" ], function( i, name ) { var orig = jQuery.css( elem, type ), ret = parseFloat( orig ); - return jQuery.isNaN( ret ) ? orig : ret; + return jQuery.isNumeric( ret ) ? ret : orig; // Set the width or height on the element (default to pixels if value is unitless) } else { @@ -8312,5 +9295,6 @@ jQuery.each([ "Height", "Width" ], function( i, name ) { }); +// Expose jQuery to the global object window.jQuery = window.$ = jQuery; -})(window); +})( window ); diff --git a/feincms/static/feincms/jquery-1.7.min.js b/feincms/static/feincms/jquery-1.7.min.js new file mode 100644 index 000000000..3ca5e0f5d --- /dev/null +++ b/feincms/static/feincms/jquery-1.7.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7 jquery.com | jquery.org/license */ +(function(a,b){function cA(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cx(a){if(!cm[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cn||(cn=c.createElement("iframe"),cn.frameBorder=cn.width=cn.height=0),b.appendChild(cn);if(!co||!cn.createElement)co=(cn.contentWindow||cn.contentDocument).document,co.write((c.compatMode==="CSS1Compat"?"":"")+""),co.close();d=co.createElement(a),co.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cn)}cm[a]=e}return cm[a]}function cw(a,b){var c={};f.each(cs.concat.apply([],cs.slice(0,b)),function(){c[this]=a});return c}function cv(){ct=b}function cu(){setTimeout(cv,0);return ct=f.now()}function cl(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ck(){try{return new a.XMLHttpRequest}catch(b){}}function ce(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bB(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function br(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bi,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bq(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bp(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bp)}function bp(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bo(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bn(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bm(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(){return!0}function M(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.add(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return a!=null&&m.test(a)&&!isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,unknownElems:!!a.getElementsByTagName("nav").length,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",enctype:!!c.createElement("form").enctype,submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.lastChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-999px",top:"-999px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;f(function(){var a,b,d,e,g,h,i=1,j="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",l="visibility:hidden;border:0;",n="style='"+j+"border:5px solid #000;padding:0;'",p="
"+""+"
";m=c.getElementsByTagName("body")[0];!m||(a=c.createElement("div"),a.style.cssText=l+"width:0;height:0;position:static;top:0;margin-top:"+i+"px",m.insertBefore(a,m.firstChild),o=c.createElement("div"),o.style.cssText=j+l,o.innerHTML=p,a.appendChild(o),b=o.firstChild,d=b.firstChild,g=b.nextSibling.firstChild.firstChild,h={doesNotAddBorder:d.offsetTop!==5,doesAddBorderForTableAndCells:g.offsetTop===5},d.style.position="fixed",d.style.top="20px",h.fixedPosition=d.offsetTop===20||d.offsetTop===15,d.style.position=d.style.top="",b.style.overflow="hidden",b.style.position="relative",h.subtractsBorderForOverflowNotVisible=d.offsetTop===-5,h.doesNotIncludeMarginInBodyOffset=m.offsetTop!==i,m.removeChild(a),o=a=null,f.extend(k,h))}),o.innerHTML="",n.removeChild(o),o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[f.expando]:a[f.expando]&&f.expando,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[f.expando]=n=++f.uuid:n=f.expando),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[f.expando]:f.expando;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)?b=b:b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" "));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];if(!arguments.length){if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}return b}e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!a||j===3||j===8||j===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g},removeAttr:function(a,b){var c,d,e,g,h=0;if(a.nodeType===1){d=(b||"").split(p),g=d.length;for(;h=0}})});var z=/\.(.*)$/,A=/^(?:textarea|input|select)$/i,B=/\./g,C=/ /g,D=/[^\w\s.|`]/g,E=/^([^\.]*)?(?:\.(.+))?$/,F=/\bhover(\.\S+)?/,G=/^key/,H=/^(?:mouse|contextmenu)|click/,I=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,J=function(a){var b=I.exec(a);b&& +(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},K=function(a,b){return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||a.id===b[2])&&(!b[3]||b[3].test(a.className))},L=function(a){return f.event.special.hover?a:a.replace(F,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=L(c).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"",(g||!e)&&c.preventDefault();if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,n=null;for(m=e.parentNode;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l=0:t===b&&(t=o[s]=r.quick?K(m,r.quick):f(m).is(s)),t&&q.push(r);q.length&&j.push({elem:m,matches:q})}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),G.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),H.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y="abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",Z=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,_=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,ba=/<([\w:]+)/,bb=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bk=X(c);bj.optgroup=bj.option,bj.tbody=bj.tfoot=bj.colgroup=bj.caption=bj.thead,bj.th=bj.td,f.support.htmlSerialize||(bj._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after" +,arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Z,""):null;if(typeof a=="string"&&!bd.test(a)&&(f.support.leadingWhitespace||!$.test(a))&&!bj[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(_,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bn(a,d),e=bo(a),g=bo(d);for(h=0;e[h];++h)g[h]&&bn(e[h],g[h])}if(b){bm(a,d);if(c){e=bo(a),g=bo(d);for(h=0;e[h];++h)bm(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bc.test(k))k=b.createTextNode(k);else{k=k.replace(_,"<$1>");var l=(ba.exec(k)||["",""])[1].toLowerCase(),m=bj[l]||bj._default,n=m[0],o=b.createElement("div");b===c?bk.appendChild(o):X(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=bb.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&$.test(k)&&o.insertBefore(b.createTextNode($.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bt.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bs,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bs.test(g)?g.replace(bs,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bB(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bC=function(a,c){var d,e,g;c=c.replace(bu,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bD=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bv.test(f)&&bw.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bB=bC||bD,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bF=/%20/g,bG=/\[\]$/,bH=/\r?\n/g,bI=/#.*$/,bJ=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bK=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bL=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bM=/^(?:GET|HEAD)$/,bN=/^\/\//,bO=/\?/,bP=/)<[^<]*)*<\/script>/gi,bQ=/^(?:select|textarea)/i,bR=/\s+/,bS=/([?&])_=[^&]*/,bT=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bU=f.fn.load,bV={},bW={},bX,bY,bZ=["*/"]+["*"];try{bX=e.href}catch(b$){bX=c.createElement("a"),bX.href="",bX=bX.href}bY=bT.exec(bX.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bU)return bU.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bP,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bQ.test(this.nodeName)||bK.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bH,"\r\n")}}):{name:b.name,value:c.replace(bH,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?cb(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),cb(a,b);return a},ajaxSettings:{url:bX,isLocal:bL.test(bY[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bZ},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:b_(bV),ajaxTransport:b_(bW),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cd(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=ce(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bJ.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bI,"").replace(bN,bY[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bR),d.crossDomain==null&&(r=bT.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bY[1]&&r[2]==bY[2]&&(r[3]||(r[1]==="http:"?80:443))==(bY[3]||(bY[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),ca(bV,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bM.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bO.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bS,"$1_="+x);d.url=y+(y===d.url?(bO.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bZ+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=ca(bW,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)cc(g,a[g],c,e);return d.join("&").replace(bF,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cf=f.now(),cg=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cf++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cg.test(b.url)||e&&cg.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cg,l),b.url===j&&(e&&(k=k.replace(cg,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ch=a.ActiveXObject?function(){for(var a in cj)cj[a](0,1)}:!1,ci=0,cj;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ck()||cl()}:ck,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ch&&delete cj[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++ci,ch&&(cj||(cj={},f(a).unload(ch)),cj[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cm={},cn,co,cp=/^(?:toggle|show|hide)$/,cq=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cr,cs=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],ct;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cw("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cz.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cz.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cA(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cA(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/feincms/templates/admin/feincms/fe_editor.html b/feincms/templates/admin/feincms/fe_editor.html index efa99087a..62cf3bbba 100644 --- a/feincms/templates/admin/feincms/fe_editor.html +++ b/feincms/templates/admin/feincms/fe_editor.html @@ -3,7 +3,7 @@ {% block extrahead %}{{ block.super }} - + + + {% endblock %} diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index 294753a98..bc31a75d8 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -6,7 +6,7 @@ - + - + - + - + {% endblock %} diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index bc31a75d8..e20bdd703 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -7,7 +7,7 @@ - + {% endif %} - {% endwith %} +{% endif %}{% endfor %} +{% endwith %} {% endblock %} {% block after_related_objects %} {# as good a place as any... #} From a02eef13427a1a1c5df5e8a10256eda061f84b65 Mon Sep 17 00:00:00 2001 From: Olekasnadr Gula Date: Thu, 23 Feb 2012 17:06:02 +0200 Subject: [PATCH 0217/1590] Updated add_view and change_view to reflect change_view signature change in Django 1.4b. This should work in the future if signatures changes again. Use of kwargs only (without args) should be safe, because admin views are called using keyword arguments. --- feincms/admin/item_editor.py | 14 ++++++++------ feincms/module/page/models.py | 12 +++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 5fda63f36..90c04cbd0 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -198,7 +198,7 @@ def get_extra_context(self, request): return extra_context - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, **kwargs): context = {} # insert dummy object as 'original' so template code can grab defaults @@ -213,10 +213,11 @@ def add_view(self, request, form_url='', extra_context=None): context['original'].template_key = request.POST['template_key'] context.update(self.get_extra_context(request)) - context.update(extra_context or {}) - return super(ItemEditor, self).add_view(request, form_url, extra_context=context) + context.update(kwargs.get('extra_context', {})) + kwargs['extra_context'] = context + return super(ItemEditor, self).add_view(request, **kwargs) - def change_view(self, request, object_id, extra_context=None): + def change_view(self, request, object_id, **kwargs): # Recognize frontend editing requests # This is done here so that the developer does not need to add # additional entries to # urls.py or something... @@ -227,8 +228,9 @@ def change_view(self, request, object_id, extra_context=None): context = {} context.update(self.get_extra_context(request)) - context.update(extra_context or {}) - return super(ItemEditor, self).change_view(request, object_id, extra_context=context) + context.update(kwargs.get('extra_context', {})) + kwargs['extra_context'] = context + return super(ItemEditor, self).change_view(request, object_id, **kwargs) # The next two add support for sending a "saving done" signal as soon # as all relevant data have been saved (especially all foreign key relations) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 9b31cd113..e36c8d0ba 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -622,12 +622,10 @@ def _actions_column(self, page): return actions - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, **kwargs): # Preserve GET parameters - return super(PageAdmin, self).add_view( - request=request, - form_url=request.get_full_path(), - extra_context=extra_context) + kwargs['form_url'] = request.get_full_path() + return super(PageAdmin, self).add_view(request, **kwargs) def response_add(self, request, obj, *args, **kwargs): response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) @@ -657,9 +655,9 @@ def response_add(self, request, obj, *args, **kwargs): def _refresh_changelist_caches(self, *args, **kwargs): self._visible_pages = list(self.model.objects.active().values_list('id', flat=True)) - def change_view(self, request, object_id, extra_context=None): + def change_view(self, request, object_id, **kwargs): try: - return super(PageAdmin, self).change_view(request, object_id, extra_context) + return super(PageAdmin, self).change_view(request, object_id, **kwargs) except PermissionDenied: from django.contrib import messages messages.add_message(request, messages.ERROR, _("You don't have the necessary permissions to edit this object")) From d7fe25edceae23d8a4c428ff5a573f83f641e6a1 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn Date: Fri, 24 Feb 2012 16:10:55 +0000 Subject: [PATCH 0218/1590] Use _default_manager rather than objects in the datepublisher. --- feincms/module/extensions/datepublisher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index d307eaebd..83401ce52 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -64,8 +64,8 @@ def granular_save(obj, *args, **kwargs): cls.save = granular_save # Append publication date active check - if hasattr(cls.objects, 'add_to_active_filters'): - cls.objects.add_to_active_filters( + if hasattr(cls._default_manager, 'add_to_active_filters'): + cls._default_manager.add_to_active_filters( Q(publication_date__lte=granular_now) & (Q(publication_end_date__isnull=True) | Q(publication_end_date__gt=granular_now)), key='datepublisher') From b02917692ede5bce52113dc0fdf58e82ed3a87be Mon Sep 17 00:00:00 2001 From: Jay Yu Date: Mon, 27 Feb 2012 17:04:11 +1100 Subject: [PATCH 0219/1590] Fixed a KeyError when apps listed in INSTALLED_APPS are imported more than once. E.g. nexus.autodiscover() --- feincms/module/page/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 0265c803d..5c3a77332 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -706,7 +706,7 @@ def add_extension_options(cls, *f): def __init__(self, *args, **kwargs): ensure_completely_loaded() - if len(Page._feincms_templates) > 4: + if len(Page._feincms_templates) > 4 and 'template_key' in self.radio_fields: del(self.radio_fields['template_key']) super(PageAdmin, self).__init__(*args, **kwargs) From 450c14ade84fd3bf20b4d4d12fd410c65e48ff88 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 27 Feb 2012 12:12:10 +0100 Subject: [PATCH 0220/1590] siblings_along_path_to: If the current node is not in the tree, it should show at least the top level navigation, so extract top level and always include that in the result set. --- feincms/module/page/templatetags/feincms_page_tags.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 584e825b9..727028039 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -393,8 +393,10 @@ def siblings_along_path_to(page_list, page2): # NOTE: This assumes that the input list actually is complete (ie. comes from # feincms_navigation). We'll cope with the fall-out of that assumption # when it happens... - ancestors = [a_page for a_page in page_list + ancestors = [a_page for a_page in page_list if _is_equal_or_parent_of(a_page, page2)] + top_level = min((a_page.level for a_page in page_list)) + if not ancestors: # Happens when we sit on a page outside the navigation tree # so fake an active root page to avoid a get_ancestors() db call @@ -404,6 +406,7 @@ def siblings_along_path_to(page_list, page2): siblings = [a_page for a_page in page_list if a_page.parent_id == page2.id or + a_page.level == top_level or any((_is_sibling_of(a_page, a) for a in ancestors))] return siblings except AttributeError: From 22415b16699461ac598411341cf1189687d6e532 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 28 Feb 2012 17:00:48 +0100 Subject: [PATCH 0221/1590] We do not need the /media/ lines in the MANIFEST.in file anymore --- MANIFEST.in | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 25d01403e..5549b42aa 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,11 +1,6 @@ include AUTHORS include LICENSE include README.rst -recursive-include feincms/media *.png -recursive-include feincms/media *.jpg -recursive-include feincms/media *.gif -recursive-include feincms/media *.js -recursive-include feincms/media *.css recursive-include feincms/static *.png recursive-include feincms/static *.jpg recursive-include feincms/static *.gif From a00470677020de0d2c7f0dd22b4e0371be3a088c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 20 Feb 2012 16:13:16 +0100 Subject: [PATCH 0222/1590] ItemEditor: Be a bit more future proof by passing more values as keyword arguments --- feincms/admin/item_editor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 69bab16de..5fda63f36 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -214,7 +214,7 @@ def add_view(self, request, form_url='', extra_context=None): context.update(self.get_extra_context(request)) context.update(extra_context or {}) - return super(ItemEditor, self).add_view(request, form_url, context) + return super(ItemEditor, self).add_view(request, form_url, extra_context=context) def change_view(self, request, object_id, extra_context=None): # Recognize frontend editing requests @@ -228,7 +228,7 @@ def change_view(self, request, object_id, extra_context=None): context = {} context.update(self.get_extra_context(request)) context.update(extra_context or {}) - return super(ItemEditor, self).change_view(request, object_id, context) + return super(ItemEditor, self).change_view(request, object_id, extra_context=context) # The next two add support for sending a "saving done" signal as soon # as all relevant data have been saved (especially all foreign key relations) From 5785b5f6caeb193f941172ff2c6d19c750387191 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 29 Feb 2012 08:27:49 +0100 Subject: [PATCH 0223/1590] Convert ImageContent to use the bundled thumbnail functions instead They might not be the best thumbnail functions around, but we do not want to endorse a particular 3rd party thumbnail library for now. --- docs/releases/1.6.rst | 3 ++- feincms/content/image/models.py | 35 +++++++++++++++------------------ 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/docs/releases/1.6.rst b/docs/releases/1.6.rst index c4d059910..b51a129ec 100644 --- a/docs/releases/1.6.rst +++ b/docs/releases/1.6.rst @@ -48,7 +48,8 @@ FeinCMS 1.6 release notes (upcoming) icons out-of-the-box. * ``ImageContent`` now accepts optional ``FORMAT_CHOICES`` for use with - ``easy_thumbnails``, as well as ``caption`` and ``alt_text`` fields. + FeinCMS' bundled thumbnailers, as well as ``caption`` and ``alt_text`` fields. + TODO: Insert migration instructions here for existing installations of FeinCMS. * ``FileContent`` now displays the size of the file in the default template, and uses ``span`` elements to allow styling of the title / size. diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index cf136d4a7..bedcedd6f 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -11,6 +11,8 @@ from django.utils.translation import ugettext_lazy as _ from feincms import settings +from feincms.templatetags import feincms_thumbnail + class ImageContent(models.Model): # You should probably use @@ -25,18 +27,16 @@ class ImageContent(models.Model): ('left', 'Left'), ('right', 'Right'), ), - SIZE_CHOICES=( + FORMAT_CHOICES=( ('', 'Do not resize'), - ('100x100 crop', 'Square Thumbnail'), - ('200x450 upscale crop', 'Medium Portait'), - ('1000x1000', 'Large'), + ('cropscale:100x100', 'Square Thumbnail'), + ('cropscale:200x450', 'Medium Portait'), + ('thumbnail:1000x1000', 'Large'), )) - Note that SIZE_CHOICES is optional, requires easy_thumbnails to be - installed. - - Also note that only boolean easy_thumbnail arguments are supported, - not those with values such as "quality=90". + Note that FORMAT_CHOICES is optional. The part before the colon + corresponds to the template filters in the ``feincms_thumbnail`` + template filter library. """ image = models.ImageField( @@ -59,17 +59,14 @@ def render(self, **kwargs): ], {'content': self}) def get_image(self): - try: - from easy_thumbnails.files import get_thumbnailer - except ImportError: + type, separator, size = getattr(self, 'format', '').partition(':') + if not size: return self.image - else: - size, space, options = getattr(self, 'format', '').partition(' ') - thumbnailer = get_thumbnailer(self.image) - thumbnail_options = {'size': size.split('x')} - for option in options.split(' '): - thumbnail_options[option] = True - return thumbnailer.get_thumbnail(thumbnail_options) + + thumbnailer = { + 'cropscale': feincms_thumbnail.CropscaleThumbnailer, + }.get(type, feincms_thumbnail.Thumbnailer) + return thumbnailer(self.image, size) @classmethod def initialize_type(cls, POSITION_CHOICES=None, FORMAT_CHOICES=None): From be27c398a3b4638f998d1bd2abc0b4580e2158ce Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 29 Feb 2012 08:36:44 +0100 Subject: [PATCH 0224/1590] Add some migration instructions for the new ImageContent --- docs/releases/1.6.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/releases/1.6.rst b/docs/releases/1.6.rst index b51a129ec..93e245cae 100644 --- a/docs/releases/1.6.rst +++ b/docs/releases/1.6.rst @@ -49,7 +49,19 @@ FeinCMS 1.6 release notes (upcoming) * ``ImageContent`` now accepts optional ``FORMAT_CHOICES`` for use with FeinCMS' bundled thumbnailers, as well as ``caption`` and ``alt_text`` fields. - TODO: Insert migration instructions here for existing installations of FeinCMS. + +.. note:: + + If you are upgrading from an earlier version of FeinCMS, you'll have to + add the new database columns yourself or use a migration tool like South + to do it for you. Instructions for MySQL and the page module follow:: + + ALTER TABLE page_page_imagecontent ADD COLUMN `alt_text` varchar(255) NOT NULL; + ALTER TABLE page_page_imagecontent ADD COLUMN `caption` varchar(255) NOT NULL; + + If you want to use ``FORMAT_CHOICES``:: + + ALTER TABLE page_page_imagecontent ADD COLUMN `format` varchar(64) NOT NULL; * ``FileContent`` now displays the size of the file in the default template, and uses ``span`` elements to allow styling of the title / size. From aeb4455111264a25bd93950675b3ab24e0cfbf76 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 00:36:09 +0100 Subject: [PATCH 0225/1590] siblings_along_path: Make sure we don't take the min() of an empty list. --- feincms/module/page/templatetags/feincms_page_tags.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 727028039..0d8dd718b 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -395,7 +395,9 @@ def siblings_along_path_to(page_list, page2): # when it happens... ancestors = [a_page for a_page in page_list if _is_equal_or_parent_of(a_page, page2)] - top_level = min((a_page.level for a_page in page_list)) + top_level = 1 + if page_list: + top_level = min((a_page.level for a_page in page_list)) if not ancestors: # Happens when we sit on a page outside the navigation tree From 0ec81d727c4dd819c53b25cdf8aa90d2eb8b7106 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 12:20:36 +0100 Subject: [PATCH 0226/1590] MediaFile: Move admin presentation methods to MediaFileAdmin where they conceptually belong --- feincms/module/medialibrary/models.py | 121 +++++++++++++------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index cb4e29933..8d8ce4bcc 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -176,46 +176,6 @@ def __unicode__(self): def get_absolute_url(self): return self.file.url - def file_type(self): - t = self.filetypes_dict[self.type] - if self.type == 'image': - # get_image_dimensions is expensive / slow if the storage is not local filesystem (indicated by availability the path property) - try: - self.file.path - except NotImplementedError: - return t - try: - from django.core.files.images import get_image_dimensions - d = get_image_dimensions(self.file.file) - if d: t += " %d×%d" % ( d[0], d[1] ) - except IOError, e: - t += " (%s)" % e.strerror - return t - file_type.admin_order_field = 'type' - file_type.short_description = _('file type') - file_type.allow_tags = True - - def file_info(self): - """ - Method for showing the file name in admin. - - Note: This also includes a hidden field that can be used to extract - the file name later on, this can be used to access the file name from - JS, like for example a TinyMCE connector shim. - """ - from feincms.utils import shorten_string - return u' %s
%s, %s' % ( - self.id, - self.file.name, - self.id, - shorten_string(os.path.basename(self.file.name), max_length=40), - self.file_type(), - self.formatted_file_size(), - ) - file_info.admin_order_field = 'file' - file_info.short_description = _('file info') - file_info.allow_tags = True - def determine_file_type(self, name): """ >>> t = MediaFileBase() @@ -328,25 +288,6 @@ def __unicode__(self): return self.caption #------------------------------------------------------------------------- -def admin_thumbnail(obj): - if obj.type == 'image': - image = None - try: - image = feincms_thumbnail.thumbnail(obj.file.name, '100x100') - except: - pass - - if image: - return mark_safe(u""" - - - """ % { - 'url': obj.file.url, - 'image': image,}) - return '' -admin_thumbnail.short_description = _('Preview') -admin_thumbnail.allow_tags = True - #------------------------------------------------------------------------- def assign_category(modeladmin, request, queryset): class AddCategoryForm(forms.Form): @@ -431,7 +372,7 @@ class MediaFileAdmin(admin.ModelAdmin): form = MediaFileAdminForm date_hierarchy = 'created' inlines = [admin_translationinline(MediaFileTranslation)] - list_display = [admin_thumbnail, '__unicode__', 'file_info', 'formatted_created'] + list_display = ['admin_thumbnail', '__unicode__', 'file_info', 'formatted_created'] list_display_links = ['__unicode__'] list_filter = ['type', 'categories'] list_per_page = 25 @@ -455,6 +396,66 @@ def changelist_view(self, request, extra_context=None): extra_context['categories'] = Category.objects.order_by('title') return super(MediaFileAdmin, self).changelist_view(request, extra_context=extra_context) + def admin_thumbnail(self, obj): + if obj.type == 'image': + image = None + try: + image = feincms_thumbnail.thumbnail(obj.file.name, '100x100') + except: + pass + + if image: + return mark_safe(u""" + + + """ % { + 'url': obj.file.url, + 'image': image,}) + return '' + admin_thumbnail.short_description = _('Preview') + admin_thumbnail.allow_tags = True + + def file_type(self, obj): + t = obj.filetypes_dict[obj.type] + if obj.type == 'image': + # get_image_dimensions is expensive / slow if the storage is not local filesystem (indicated by availability the path property) + try: + obj.file.path + except NotImplementedError: + return t + try: + from django.core.files.images import get_image_dimensions + d = get_image_dimensions(obj.file.file) + if d: + t += " %d×%d" % ( d[0], d[1] ) + except IOError, e: + t += " (%s)" % e.strerror + return t + file_type.admin_order_field = 'type' + file_type.short_description = _('file type') + file_type.allow_tags = True + + def file_info(self, obj): + """ + Method for showing the file name in admin. + + Note: This also includes a hidden field that can be used to extract + the file name later on, this can be used to access the file name from + JS, like for example a TinyMCE connector shim. + """ + from feincms.utils import shorten_string + return u' %s
%s, %s' % ( + obj.id, + obj.file.name, + obj.id, + shorten_string(os.path.basename(obj.file.name), max_length=40), + self.file_type(obj), + obj.formatted_file_size(), + ) + file_info.admin_order_field = 'file' + file_info.short_description = _('file info') + file_info.allow_tags = True + @staticmethod @csrf_protect @permission_required('medialibrary.add_mediafile') From 2c22b1e764d20cb94affb0b8d9f976edc53faf70 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 12:21:14 +0100 Subject: [PATCH 0227/1590] MediaFileAdmin: Move admin form into own file --- feincms/module/medialibrary/forms.py | 40 +++++++++++++++++++++++++++ feincms/module/medialibrary/models.py | 27 ++---------------- 2 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 feincms/module/medialibrary/forms.py diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py new file mode 100644 index 000000000..8f47be651 --- /dev/null +++ b/feincms/module/medialibrary/forms.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +import os + +from django import forms +from django.conf import settings +from django.utils.translation import ugettext_lazy as _ + +from .models import MediaFile + +# ------------------------------------------------------------------------ +class MediaFileAdminForm(forms.ModelForm): + class Meta: + model = MediaFile + + def __init__(self, *args, **kwargs): + super(MediaFileAdminForm, self).__init__(*args, **kwargs) + if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: + self.original_name = self.instance.file.name + + def gen_fname(instance, filename): + self.instance.file.storage.delete(self.original_name) + return self.original_name + self.instance.file.field.generate_filename = gen_fname + + def clean_file(self): + if settings.FEINCMS_MEDIAFILE_OVERWRITE and hasattr(self, 'original_name'): + new_base, new_ext = os.path.splitext(self.cleaned_data['file'].name) + old_base, old_ext = os.path.splitext(self.original_name) + + if new_ext.lower() != old_ext.lower(): + raise forms.ValidationError(_("Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)") % { 'old_ext': old_ext, 'new_ext': new_ext }) + + return self.cleaned_data['file'] + +# ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 8d8ce4bcc..b0749fce4 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -341,32 +341,9 @@ def save_as_zipfile(modeladmin, request, queryset): save_as_zipfile.short_description = _('Export selected media files as zip file') -# ------------------------------------------------------------------------ -class MediaFileAdminForm(forms.ModelForm): - class Meta: - model = MediaFile - - def __init__(self, *args, **kwargs): - super(MediaFileAdminForm, self).__init__(*args, **kwargs) - if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: - self.original_name = self.instance.file.name - - def gen_fname(instance, filename): - self.instance.file.storage.delete(self.original_name) - return self.original_name - self.instance.file.field.generate_filename = gen_fname - - def clean_file(self): - if settings.FEINCMS_MEDIAFILE_OVERWRITE and hasattr(self, 'original_name'): - new_base, new_ext = os.path.splitext(self.cleaned_data['file'].name) - old_base, old_ext = os.path.splitext(self.original_name) - - if new_ext.lower() != old_ext.lower(): - raise forms.ValidationError(_("Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)") % { 'old_ext': old_ext, 'new_ext': new_ext }) - - return self.cleaned_data['file'] - # ----------------------------------------------------------------------- +from .forms import MediaFileAdminForm + class MediaFileAdmin(admin.ModelAdmin): save_on_top = True form = MediaFileAdminForm From 579d575bbd1890e7b96a9ed2945831c58217f4f6 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 12:40:27 +0100 Subject: [PATCH 0228/1590] MediaFileAdmin: Move admin stuff into admin.py, really no need to have it in models.py --- feincms/module/medialibrary/admin.py | 215 +++++++++++++++++++++++++- feincms/module/medialibrary/models.py | 209 +------------------------ 2 files changed, 219 insertions(+), 205 deletions(-) diff --git a/feincms/module/medialibrary/admin.py b/feincms/module/medialibrary/admin.py index ad6d7bdbc..d05a4d50c 100644 --- a/feincms/module/medialibrary/admin.py +++ b/feincms/module/medialibrary/admin.py @@ -1,6 +1,219 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +import os + +from django import forms +from django.conf import settings as django_settings from django.contrib import admin +from django.contrib import messages +from django.contrib.auth.decorators import permission_required +from django.contrib.sites.models import Site +from django.core.files.images import get_image_dimensions +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.shortcuts import render_to_response +from django.template.context import RequestContext +from django.template.defaultfilters import filesizeformat +from django.utils.safestring import mark_safe +from django.utils.translation import ungettext, ugettext_lazy as _ +from django.views.decorators.csrf import csrf_protect + +from ...templatetags import feincms_thumbnail +from ...translations import admin_translationinline, lookup_translations + +from .models import Category, MediaFile, MediaFileTranslation +from .forms import MediaFileAdminForm + +# ----------------------------------------------------------------------- +class CategoryAdmin(admin.ModelAdmin): + list_display = ['path'] + list_filter = ['parent'] + list_per_page = 25 + search_fields = ['title'] + prepopulated_fields = { 'slug': ('title',), } + +#------------------------------------------------------------------------- +def assign_category(modeladmin, request, queryset): + class AddCategoryForm(forms.Form): + _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) + category = forms.ModelChoiceField(Category.objects.all()) + + form = None + if 'apply' in request.POST: + form = AddCategoryForm(request.POST) + if form.is_valid(): + category = form.cleaned_data['category'] + + count = 0 + for mediafile in queryset: + category.mediafile_set.add(mediafile) + count += 1 + + message = ungettext('Successfully added %(count)d media file to %(category)s.', + 'Successfully added %(count)d media files to %(category)s.', + count) % {'count':count, 'category':category} + modeladmin.message_user(request, message) + return HttpResponseRedirect(request.get_full_path()) + if 'cancel' in request.POST: + return HttpResponseRedirect(request.get_full_path()) + + if not form: + form = AddCategoryForm(initial={ + '_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME), + }) + + return render_to_response('admin/medialibrary/add_to_category.html', { + 'mediafiles': queryset, + 'category_form': form, + }, context_instance=RequestContext(request)) + +assign_category.short_description = _('Add selected media files to category') + +#------------------------------------------------------------------------- +def save_as_zipfile(modeladmin, request, queryset): + from .zip import export_zipfile + + site = Site.objects.get_current() + try: + zip_name = export_zipfile(site, queryset) + messages.info(request, _("ZIP file exported as %s") % zip_name) + except Exception, e: + messages.error(request, _("ZIP file export failed: %s") % str(e)) + return + + return HttpResponseRedirect(os.path.join(django_settings.MEDIA_URL, zip_name)) + +save_as_zipfile.short_description = _('Export selected media files as zip file') -from feincms.module.medialibrary.models import Category, CategoryAdmin, MediaFile, MediaFileAdmin +# ------------------------------------------------------------------------ +class MediaFileAdmin(admin.ModelAdmin): + save_on_top = True + form = MediaFileAdminForm + date_hierarchy = 'created' + inlines = [admin_translationinline(MediaFileTranslation)] + list_display = ['admin_thumbnail', '__unicode__', 'file_info', 'formatted_created'] + list_display_links = ['__unicode__'] + list_filter = ['type', 'categories'] + list_per_page = 25 + search_fields = ['copyright', 'file', 'translations__caption'] + filter_horizontal = ("categories",) + actions = [assign_category, save_as_zipfile] + def get_urls(self): + from django.conf.urls.defaults import url, patterns + + urls = super(MediaFileAdmin, self).get_urls() + my_urls = patterns('', + url(r'^mediafile-bulk-upload/$', self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, name='mediafile_bulk_upload') + ) + + return my_urls + urls + + def changelist_view(self, request, extra_context=None): + if extra_context is None: + extra_context = {} + extra_context['categories'] = Category.objects.order_by('title') + return super(MediaFileAdmin, self).changelist_view(request, extra_context=extra_context) + + def admin_thumbnail(self, obj): + if obj.type == 'image': + image = None + try: + image = feincms_thumbnail.thumbnail(obj.file.name, '100x100') + except: + pass + + if image: + return mark_safe(u""" + + + """ % { + 'url': obj.file.url, + 'image': image,}) + return '' + admin_thumbnail.short_description = _('Preview') + admin_thumbnail.allow_tags = True + + def formatted_file_size(self, obj): + return filesizeformat(obj.file_size) + formatted_file_size.short_description = _("file size") + formatted_file_size.admin_order_field = 'file_size' + + def formatted_created(self, obj): + return obj.created.strftime("%Y-%m-%d") + formatted_created.short_description = _("created") + formatted_created.admin_order_field = 'created' + + def file_type(self, obj): + t = obj.filetypes_dict[obj.type] + if obj.type == 'image': + # get_image_dimensions is expensive / slow if the storage is not local filesystem (indicated by availability the path property) + try: + obj.file.path + except NotImplementedError: + return t + try: + d = get_image_dimensions(obj.file.file) + if d: + t += " %d×%d" % ( d[0], d[1] ) + except IOError, e: + t += " (%s)" % e.strerror + return t + file_type.admin_order_field = 'type' + file_type.short_description = _('file type') + file_type.allow_tags = True + + def file_info(self, obj): + """ + Method for showing the file name in admin. + + Note: This also includes a hidden field that can be used to extract + the file name later on, this can be used to access the file name from + JS, like for example a TinyMCE connector shim. + """ + from feincms.utils import shorten_string + return u' %s
%s, %s' % ( + obj.id, + obj.file.name, + obj.id, + shorten_string(os.path.basename(obj.file.name), max_length=40), + self.file_type(obj), + self.formatted_file_size(obj), + ) + file_info.admin_order_field = 'file' + file_info.short_description = _('file info') + file_info.allow_tags = True + + @staticmethod + @csrf_protect + @permission_required('medialibrary.add_mediafile') + def bulk_upload(request): + from .zip import import_zipfile + + if request.method == 'POST' and 'data' in request.FILES: + try: + count = import_zipfile(request.POST.get('category'), request.POST.get('overwrite', False), request.FILES['data']) + messages.info(request, _("%d files imported") % count) + except Exception, e: + messages.error(request, _("ZIP import failed: %s") % str(e)) + else: + messages.error(request, _("No input file given")) + + return HttpResponseRedirect(reverse('admin:medialibrary_mediafile_changelist')) + + def queryset(self, request): + return super(MediaFileAdmin, self).queryset(request).transform(lookup_translations()) + + def save_model(self, request, obj, form, change): + obj.purge_translation_cache() + return super(MediaFileAdmin, self).save_model(request, obj, form, change) + +# ------------------------------------------------------------------------ admin.site.register(Category, CategoryAdmin) admin.site.register(MediaFile, MediaFileAdmin) + +# ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index b0749fce4..07ecb1cbb 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -15,26 +15,13 @@ except ImportError: import Image -from django import forms -from django.conf import settings as django_settings -from django.contrib import admin, messages -from django.contrib.auth.decorators import permission_required -from django.contrib.sites.models import Site -from django.core.urlresolvers import reverse from django.db import models -from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response -from django.template.context import RequestContext -from django.template.defaultfilters import filesizeformat, slugify -from django.utils.safestring import mark_safe -from django.utils.translation import ungettext, ugettext_lazy as _ -from django.views.decorators.csrf import csrf_protect +from django.template.defaultfilters import slugify +from django.utils.translation import ugettext_lazy as _ from feincms import settings from feincms.models import ExtensionsMixin -from feincms.templatetags import feincms_thumbnail -from feincms.translations import (TranslatedObjectMixin, Translation, - TranslatedObjectManager, admin_translationinline, lookup_translations) +from feincms.translations import TranslatedObjectMixin, Translation, TranslatedObjectManager # ------------------------------------------------------------------------ class CategoryManager(models.Manager): @@ -88,13 +75,6 @@ def path_list(self): def path(self): return ' - '.join((f.title for f in self.path_list())) -class CategoryAdmin(admin.ModelAdmin): - list_display = ['path'] - list_filter = ['parent'] - list_per_page = 25 - search_fields = ['title'] - prepopulated_fields = { 'slug': ('title',), } - # ------------------------------------------------------------------------ class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): """ @@ -123,16 +103,6 @@ class Meta: filetypes = [ ] filetypes_dict = { } - def formatted_file_size(self): - return filesizeformat(self.file_size) - formatted_file_size.short_description = _("file size") - formatted_file_size.admin_order_field = 'file_size' - - def formatted_created(self): - return self.created.strftime("%Y-%m-%d") - formatted_created.short_description = _("created") - formatted_created.admin_order_field = 'created' - @classmethod def reconfigure(cls, upload_to=None, storage=None): f = cls._meta.get_field('file') @@ -268,9 +238,10 @@ def save(self, *args, **kwargs): class MediaFile(MediaFileBase): @classmethod def register_extension(cls, register_fn): + from .admin import MediaFileAdmin + register_fn(cls, MediaFileAdmin) -# ------------------------------------------------------------------------ # ------------------------------------------------------------------------ class MediaFileTranslation(Translation(MediaFile)): """ @@ -289,173 +260,3 @@ def __unicode__(self): #------------------------------------------------------------------------- #------------------------------------------------------------------------- -def assign_category(modeladmin, request, queryset): - class AddCategoryForm(forms.Form): - _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) - category = forms.ModelChoiceField(Category.objects.all()) - - form = None - if 'apply' in request.POST: - form = AddCategoryForm(request.POST) - if form.is_valid(): - category = form.cleaned_data['category'] - - count = 0 - for mediafile in queryset: - category.mediafile_set.add(mediafile) - count += 1 - - message = ungettext('Successfully added %(count)d media file to %(category)s.', - 'Successfully added %(count)d media files to %(category)s.', - count) % {'count':count, 'category':category} - modeladmin.message_user(request, message) - return HttpResponseRedirect(request.get_full_path()) - if 'cancel' in request.POST: - return HttpResponseRedirect(request.get_full_path()) - - if not form: - form = AddCategoryForm(initial={ - '_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME), - }) - - return render_to_response('admin/medialibrary/add_to_category.html', { - 'mediafiles': queryset, - 'category_form': form, - }, context_instance=RequestContext(request)) - -assign_category.short_description = _('Add selected media files to category') - -#------------------------------------------------------------------------- -def save_as_zipfile(modeladmin, request, queryset): - from .zip import export_zipfile - - site = Site.objects.get_current() - try: - zip_name = export_zipfile(site, queryset) - messages.info(request, _("ZIP file exported as %s") % zip_name) - except Exception, e: - messages.error(request, _("ZIP file export failed: %s") % str(e)) - return - - return HttpResponseRedirect(os.path.join(django_settings.MEDIA_URL, zip_name)) - -save_as_zipfile.short_description = _('Export selected media files as zip file') - -# ----------------------------------------------------------------------- -from .forms import MediaFileAdminForm - -class MediaFileAdmin(admin.ModelAdmin): - save_on_top = True - form = MediaFileAdminForm - date_hierarchy = 'created' - inlines = [admin_translationinline(MediaFileTranslation)] - list_display = ['admin_thumbnail', '__unicode__', 'file_info', 'formatted_created'] - list_display_links = ['__unicode__'] - list_filter = ['type', 'categories'] - list_per_page = 25 - search_fields = ['copyright', 'file', 'translations__caption'] - filter_horizontal = ("categories",) - actions = [assign_category, save_as_zipfile] - - def get_urls(self): - from django.conf.urls.defaults import url, patterns - - urls = super(MediaFileAdmin, self).get_urls() - my_urls = patterns('', - url(r'^mediafile-bulk-upload/$', self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, name='mediafile_bulk_upload') - ) - - return my_urls + urls - - def changelist_view(self, request, extra_context=None): - if extra_context is None: - extra_context = {} - extra_context['categories'] = Category.objects.order_by('title') - return super(MediaFileAdmin, self).changelist_view(request, extra_context=extra_context) - - def admin_thumbnail(self, obj): - if obj.type == 'image': - image = None - try: - image = feincms_thumbnail.thumbnail(obj.file.name, '100x100') - except: - pass - - if image: - return mark_safe(u""" - - - """ % { - 'url': obj.file.url, - 'image': image,}) - return '' - admin_thumbnail.short_description = _('Preview') - admin_thumbnail.allow_tags = True - - def file_type(self, obj): - t = obj.filetypes_dict[obj.type] - if obj.type == 'image': - # get_image_dimensions is expensive / slow if the storage is not local filesystem (indicated by availability the path property) - try: - obj.file.path - except NotImplementedError: - return t - try: - from django.core.files.images import get_image_dimensions - d = get_image_dimensions(obj.file.file) - if d: - t += " %d×%d" % ( d[0], d[1] ) - except IOError, e: - t += " (%s)" % e.strerror - return t - file_type.admin_order_field = 'type' - file_type.short_description = _('file type') - file_type.allow_tags = True - - def file_info(self, obj): - """ - Method for showing the file name in admin. - - Note: This also includes a hidden field that can be used to extract - the file name later on, this can be used to access the file name from - JS, like for example a TinyMCE connector shim. - """ - from feincms.utils import shorten_string - return u' %s
%s, %s' % ( - obj.id, - obj.file.name, - obj.id, - shorten_string(os.path.basename(obj.file.name), max_length=40), - self.file_type(obj), - obj.formatted_file_size(), - ) - file_info.admin_order_field = 'file' - file_info.short_description = _('file info') - file_info.allow_tags = True - - @staticmethod - @csrf_protect - @permission_required('medialibrary.add_mediafile') - def bulk_upload(request): - from .zip import import_zipfile - - if request.method == 'POST' and 'data' in request.FILES: - try: - count = import_zipfile(request.POST.get('category'), request.POST.get('overwrite', False), request.FILES['data']) - messages.info(request, _("%d files imported") % count) - except Exception, e: - messages.error(request, _("ZIP import failed: %s") % str(e)) - else: - messages.error(request, _("No input file given")) - - return HttpResponseRedirect(reverse('admin:medialibrary_mediafile_changelist')) - - def queryset(self, request): - return super(MediaFileAdmin, self).queryset(request).transform(lookup_translations()) - - def save_model(self, request, obj, form, change): - obj.purge_translation_cache() - return super(MediaFileAdmin, self).save_model(request, obj, form, change) - - -#------------------------------------------------------------------------- From d4a69bfd441d10aaf63e0f072efa494d02063f43 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 12:55:00 +0100 Subject: [PATCH 0229/1590] PageAdminForm: Move into own file --- feincms/module/page/forms.py | 137 ++++++++++++++++++++++++++++++++++ feincms/module/page/models.py | 127 +------------------------------ 2 files changed, 140 insertions(+), 124 deletions(-) create mode 100644 feincms/module/page/forms.py diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py new file mode 100644 index 000000000..74b069a41 --- /dev/null +++ b/feincms/module/page/forms.py @@ -0,0 +1,137 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +from django import forms +from django.contrib.sites.models import Site +from django.forms.models import model_to_dict +from django.forms.util import ErrorList +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ + +from feincms import ensure_completely_loaded + +from .models import Page, PageManager + +# ------------------------------------------------------------------------ +class PageAdminForm(forms.ModelForm): + never_copy_fields = ('title', 'slug', 'parent', 'active', 'override_url', + 'translation_of', '_content_title', '_page_title') + + def __init__(self, *args, **kwargs): + ensure_completely_loaded() + + if 'initial' in kwargs: + if 'parent' in kwargs['initial']: + # Prefill a few form values from the parent page + try: + page = Page.objects.get(pk=kwargs['initial']['parent']) + data = model_to_dict(page) + + for field in PageManager.exclude_from_copy: + if field in data: + del data[field] + + # These are always excluded from prefilling + for field in self.never_copy_fields: + if field in data: + del data[field] + + kwargs['initial'].update(data) + except Page.DoesNotExist: + pass + + elif 'translation_of' in kwargs['initial']: + # Only if translation extension is active + try: + page = Page.objects.get(pk=kwargs['initial']['translation_of']) + original = page.original_translation + + data = { + 'translation_of': original.id, + 'template_key': original.template_key, + 'active': original.active, + 'in_navigation': original.in_navigation, + } + + if original.parent: + try: + data['parent'] = original.parent.get_translation(kwargs['initial']['language']).id + except Page.DoesNotExist: + # ignore this -- the translation does not exist + pass + + kwargs['initial'].update(data) + except (AttributeError, Page.DoesNotExist): + pass + + super(PageAdminForm, self).__init__(*args, **kwargs) + if 'instance' in kwargs: + choices = [] + for key, template in kwargs['instance'].TEMPLATE_CHOICES: + template = kwargs['instance']._feincms_templates[key] + if template.preview_image: + choices.append((template.key, + mark_safe(u'%s %s' % ( + template.preview_image, template.key, template.title)))) + else: + choices.append((template.key, template.title)) + + self.fields['template_key'].choices = choices + + def clean(self): + cleaned_data = super(PageAdminForm, self).clean() + + # No need to think further, let the user correct errors first + if self._errors: + return cleaned_data + + current_id = None + # See the comment below on why we do not use Page.objects.active(), + # at least for now. + active_pages = Page.objects.filter(active=True) + + if self.instance: + current_id = self.instance.id + active_pages = active_pages.exclude(id=current_id) + + if hasattr(Site, 'page_set') and 'site' in cleaned_data: + active_pages = active_pages.filter(site=cleaned_data['site']) + + if not cleaned_data['active']: + # If the current item is inactive, we do not need to conduct + # further validation. Note that we only check for the flag, not + # for any other active filters. This is because we do not want + # to inspect the active filters to determine whether two pages + # really won't be active at the same time. + return cleaned_data + + if cleaned_data['override_url']: + if active_pages.filter(_cached_url=cleaned_data['override_url']).count(): + self._errors['override_url'] = ErrorList([_('This URL is already taken by an active page.')]) + del cleaned_data['override_url'] + + return cleaned_data + + if current_id: + # We are editing an existing page + parent = Page.objects.get(pk=current_id).parent + else: + # The user tries to create a new page + parent = cleaned_data['parent'] + + if parent: + new_url = '%s%s/' % (parent._cached_url, cleaned_data['slug']) + else: + new_url = '/%s/' % cleaned_data['slug'] + + if active_pages.filter(_cached_url=new_url).count(): + self._errors['active'] = ErrorList([_('This URL is already taken by another active page.')]) + del cleaned_data['active'] + + return cleaned_data + +# ------------------------------------------------------------------------ +# ------------------------------------------------------------------------ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 060798f45..7e1918b87 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -10,21 +10,16 @@ import re import warnings -from django import forms from django.core.cache import cache as django_cache from django.core.exceptions import PermissionDenied from django.conf import settings as django_settings from django.contrib.contenttypes.models import ContentType -from django.contrib.sites.models import Site from django.contrib import admin from django.core.urlresolvers import reverse from django.db import models from django.db.models import Q, signals -from django.forms.models import model_to_dict -from django.forms.util import ErrorList from django.http import Http404, HttpResponseRedirect from django.utils.datastructures import SortedDict -from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.db.transaction import commit_on_success @@ -419,126 +414,10 @@ def register_extension(cls, register_fn): signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) -# MARK: - -# ------------------------------------------------------------------------ -class PageAdminForm(forms.ModelForm): - never_copy_fields = ('title', 'slug', 'parent', 'active', 'override_url', - 'translation_of', '_content_title', '_page_title') - - def __init__(self, *args, **kwargs): - ensure_completely_loaded() - - if 'initial' in kwargs: - if 'parent' in kwargs['initial']: - # Prefill a few form values from the parent page - try: - page = Page.objects.get(pk=kwargs['initial']['parent']) - data = model_to_dict(page) - - for field in PageManager.exclude_from_copy: - if field in data: - del data[field] - - # These are always excluded from prefilling - for field in self.never_copy_fields: - if field in data: - del data[field] - - kwargs['initial'].update(data) - except Page.DoesNotExist: - pass - - elif 'translation_of' in kwargs['initial']: - # Only if translation extension is active - try: - page = Page.objects.get(pk=kwargs['initial']['translation_of']) - original = page.original_translation - - data = { - 'translation_of': original.id, - 'template_key': original.template_key, - 'active': original.active, - 'in_navigation': original.in_navigation, - } - - if original.parent: - try: - data['parent'] = original.parent.get_translation(kwargs['initial']['language']).id - except Page.DoesNotExist: - # ignore this -- the translation does not exist - pass - - kwargs['initial'].update(data) - except (AttributeError, Page.DoesNotExist): - pass - - super(PageAdminForm, self).__init__(*args, **kwargs) - if 'instance' in kwargs: - choices = [] - for key, template in kwargs['instance'].TEMPLATE_CHOICES: - template = kwargs['instance']._feincms_templates[key] - if template.preview_image: - choices.append((template.key, - mark_safe(u'%s %s' % ( - template.preview_image, template.key, template.title)))) - else: - choices.append((template.key, template.title)) - - self.fields['template_key'].choices = choices - - def clean(self): - cleaned_data = super(PageAdminForm, self).clean() - - # No need to think further, let the user correct errors first - if self._errors: - return cleaned_data - - current_id = None - # See the comment below on why we do not use Page.objects.active(), - # at least for now. - active_pages = Page.objects.filter(active=True) - - if self.instance: - current_id = self.instance.id - active_pages = active_pages.exclude(id=current_id) - - if hasattr(Site, 'page_set') and 'site' in cleaned_data: - active_pages = active_pages.filter(site=cleaned_data['site']) - - if not cleaned_data['active']: - # If the current item is inactive, we do not need to conduct - # further validation. Note that we only check for the flag, not - # for any other active filters. This is because we do not want - # to inspect the active filters to determine whether two pages - # really won't be active at the same time. - return cleaned_data - - if cleaned_data['override_url']: - if active_pages.filter(_cached_url=cleaned_data['override_url']).count(): - self._errors['override_url'] = ErrorList([_('This URL is already taken by an active page.')]) - del cleaned_data['override_url'] - - return cleaned_data - - if current_id: - # We are editing an existing page - parent = Page.objects.get(pk=current_id).parent - else: - # The user tries to create a new page - parent = cleaned_data['parent'] - - if parent: - new_url = '%s%s/' % (parent._cached_url, cleaned_data['slug']) - else: - new_url = '/%s/' % cleaned_data['slug'] - - if active_pages.filter(_cached_url=new_url).count(): - self._errors['active'] = ErrorList([_('This URL is already taken by another active page.')]) - del cleaned_data['active'] - - return cleaned_data # ------------------------------------------------------------------------ +from .forms import PageAdminForm + class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): class Media: css = {} @@ -616,7 +495,7 @@ def _actions_column(self, page): actions = super(PageAdmin, self)._actions_column(page) if editable: actions.insert(0, u'%s' % ( - page.pk, _('Add child page'), settings._HACK_ADMIN_MEDIA_IMAGES ,_('Add child page'))) + page.pk, _('Add child page'), settings._HACK_ADMIN_MEDIA_IMAGES, _('Add child page'))) actions.insert(0, u'%s' % ( preview_url, _('View on site'), settings._HACK_ADMIN_MEDIA_IMAGES, _('View on site'))) From 8430faae4cc99ed11005ff2b3e10ff50ed4ca1bf Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 13:02:52 +0100 Subject: [PATCH 0230/1590] Use relative import. --- feincms/module/page/admin.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index 9e4c55fbc..1c3c82393 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -1,6 +1,15 @@ -from django.contrib import admin +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import -from feincms.module.page.models import Page, PageAdmin +from django.contrib import admin +from .models import Page, PageAdmin +# ------------------------------------------------------------------------ admin.site.register(Page, PageAdmin) + +# ------------------------------------------------------------------------ +# ------------------------------------------------------------------------ From b236a192c5db312ec513ecda9c7293f7418304dc Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 21:28:00 +0100 Subject: [PATCH 0231/1590] Segregate the MediaFileAdmin admin.py into admin.py containing only the admin.register call and modeladmins.py, which contains the actual MediaFileAdmin. This is a stopgap measure until we figure out how to do admin.register when everything else has run (especially all other models.py that might have patched the MediaFileAdmin). --- feincms/module/medialibrary/admin.py | 207 +------------------- feincms/module/medialibrary/modeladmins.py | 215 +++++++++++++++++++++ 2 files changed, 217 insertions(+), 205 deletions(-) create mode 100644 feincms/module/medialibrary/modeladmins.py diff --git a/feincms/module/medialibrary/admin.py b/feincms/module/medialibrary/admin.py index d05a4d50c..87bd942f6 100644 --- a/feincms/module/medialibrary/admin.py +++ b/feincms/module/medialibrary/admin.py @@ -4,213 +4,10 @@ from __future__ import absolute_import -import os - -from django import forms -from django.conf import settings as django_settings from django.contrib import admin -from django.contrib import messages -from django.contrib.auth.decorators import permission_required -from django.contrib.sites.models import Site -from django.core.files.images import get_image_dimensions -from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response -from django.template.context import RequestContext -from django.template.defaultfilters import filesizeformat -from django.utils.safestring import mark_safe -from django.utils.translation import ungettext, ugettext_lazy as _ -from django.views.decorators.csrf import csrf_protect - -from ...templatetags import feincms_thumbnail -from ...translations import admin_translationinline, lookup_translations - -from .models import Category, MediaFile, MediaFileTranslation -from .forms import MediaFileAdminForm - -# ----------------------------------------------------------------------- -class CategoryAdmin(admin.ModelAdmin): - list_display = ['path'] - list_filter = ['parent'] - list_per_page = 25 - search_fields = ['title'] - prepopulated_fields = { 'slug': ('title',), } - -#------------------------------------------------------------------------- -def assign_category(modeladmin, request, queryset): - class AddCategoryForm(forms.Form): - _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) - category = forms.ModelChoiceField(Category.objects.all()) - - form = None - if 'apply' in request.POST: - form = AddCategoryForm(request.POST) - if form.is_valid(): - category = form.cleaned_data['category'] - - count = 0 - for mediafile in queryset: - category.mediafile_set.add(mediafile) - count += 1 - - message = ungettext('Successfully added %(count)d media file to %(category)s.', - 'Successfully added %(count)d media files to %(category)s.', - count) % {'count':count, 'category':category} - modeladmin.message_user(request, message) - return HttpResponseRedirect(request.get_full_path()) - if 'cancel' in request.POST: - return HttpResponseRedirect(request.get_full_path()) - - if not form: - form = AddCategoryForm(initial={ - '_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME), - }) - - return render_to_response('admin/medialibrary/add_to_category.html', { - 'mediafiles': queryset, - 'category_form': form, - }, context_instance=RequestContext(request)) - -assign_category.short_description = _('Add selected media files to category') - -#------------------------------------------------------------------------- -def save_as_zipfile(modeladmin, request, queryset): - from .zip import export_zipfile - - site = Site.objects.get_current() - try: - zip_name = export_zipfile(site, queryset) - messages.info(request, _("ZIP file exported as %s") % zip_name) - except Exception, e: - messages.error(request, _("ZIP file export failed: %s") % str(e)) - return - - return HttpResponseRedirect(os.path.join(django_settings.MEDIA_URL, zip_name)) - -save_as_zipfile.short_description = _('Export selected media files as zip file') - -# ------------------------------------------------------------------------ -class MediaFileAdmin(admin.ModelAdmin): - save_on_top = True - form = MediaFileAdminForm - date_hierarchy = 'created' - inlines = [admin_translationinline(MediaFileTranslation)] - list_display = ['admin_thumbnail', '__unicode__', 'file_info', 'formatted_created'] - list_display_links = ['__unicode__'] - list_filter = ['type', 'categories'] - list_per_page = 25 - search_fields = ['copyright', 'file', 'translations__caption'] - filter_horizontal = ("categories",) - actions = [assign_category, save_as_zipfile] - - def get_urls(self): - from django.conf.urls.defaults import url, patterns - - urls = super(MediaFileAdmin, self).get_urls() - my_urls = patterns('', - url(r'^mediafile-bulk-upload/$', self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, name='mediafile_bulk_upload') - ) - - return my_urls + urls - - def changelist_view(self, request, extra_context=None): - if extra_context is None: - extra_context = {} - extra_context['categories'] = Category.objects.order_by('title') - return super(MediaFileAdmin, self).changelist_view(request, extra_context=extra_context) - - def admin_thumbnail(self, obj): - if obj.type == 'image': - image = None - try: - image = feincms_thumbnail.thumbnail(obj.file.name, '100x100') - except: - pass - - if image: - return mark_safe(u""" - - - """ % { - 'url': obj.file.url, - 'image': image,}) - return '' - admin_thumbnail.short_description = _('Preview') - admin_thumbnail.allow_tags = True - - def formatted_file_size(self, obj): - return filesizeformat(obj.file_size) - formatted_file_size.short_description = _("file size") - formatted_file_size.admin_order_field = 'file_size' - - def formatted_created(self, obj): - return obj.created.strftime("%Y-%m-%d") - formatted_created.short_description = _("created") - formatted_created.admin_order_field = 'created' - - def file_type(self, obj): - t = obj.filetypes_dict[obj.type] - if obj.type == 'image': - # get_image_dimensions is expensive / slow if the storage is not local filesystem (indicated by availability the path property) - try: - obj.file.path - except NotImplementedError: - return t - try: - d = get_image_dimensions(obj.file.file) - if d: - t += " %d×%d" % ( d[0], d[1] ) - except IOError, e: - t += " (%s)" % e.strerror - return t - file_type.admin_order_field = 'type' - file_type.short_description = _('file type') - file_type.allow_tags = True - - def file_info(self, obj): - """ - Method for showing the file name in admin. - - Note: This also includes a hidden field that can be used to extract - the file name later on, this can be used to access the file name from - JS, like for example a TinyMCE connector shim. - """ - from feincms.utils import shorten_string - return u' %s
%s, %s' % ( - obj.id, - obj.file.name, - obj.id, - shorten_string(os.path.basename(obj.file.name), max_length=40), - self.file_type(obj), - self.formatted_file_size(obj), - ) - file_info.admin_order_field = 'file' - file_info.short_description = _('file info') - file_info.allow_tags = True - - @staticmethod - @csrf_protect - @permission_required('medialibrary.add_mediafile') - def bulk_upload(request): - from .zip import import_zipfile - - if request.method == 'POST' and 'data' in request.FILES: - try: - count = import_zipfile(request.POST.get('category'), request.POST.get('overwrite', False), request.FILES['data']) - messages.info(request, _("%d files imported") % count) - except Exception, e: - messages.error(request, _("ZIP import failed: %s") % str(e)) - else: - messages.error(request, _("No input file given")) - - return HttpResponseRedirect(reverse('admin:medialibrary_mediafile_changelist')) - - def queryset(self, request): - return super(MediaFileAdmin, self).queryset(request).transform(lookup_translations()) - def save_model(self, request, obj, form, change): - obj.purge_translation_cache() - return super(MediaFileAdmin, self).save_model(request, obj, form, change) +from .models import Category, MediaFile +from .modeladmins import CategoryAdmin, MediaFileAdmin # ------------------------------------------------------------------------ admin.site.register(Category, CategoryAdmin) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py new file mode 100644 index 000000000..95d055fca --- /dev/null +++ b/feincms/module/medialibrary/modeladmins.py @@ -0,0 +1,215 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +import os + +from django import forms +from django.conf import settings as django_settings +from django.contrib import admin +from django.contrib import messages +from django.contrib.auth.decorators import permission_required +from django.contrib.sites.models import Site +from django.core.files.images import get_image_dimensions +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.shortcuts import render_to_response +from django.template.context import RequestContext +from django.template.defaultfilters import filesizeformat +from django.utils.safestring import mark_safe +from django.utils.translation import ungettext, ugettext_lazy as _ +from django.views.decorators.csrf import csrf_protect + +from ...templatetags import feincms_thumbnail +from ...translations import admin_translationinline, lookup_translations + +from .models import Category, MediaFileTranslation +from .forms import MediaFileAdminForm + +# ----------------------------------------------------------------------- +class CategoryAdmin(admin.ModelAdmin): + list_display = ['path'] + list_filter = ['parent'] + list_per_page = 25 + search_fields = ['title'] + prepopulated_fields = { 'slug': ('title',), } + +#------------------------------------------------------------------------- +def assign_category(modeladmin, request, queryset): + class AddCategoryForm(forms.Form): + _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) + category = forms.ModelChoiceField(Category.objects.all()) + + form = None + if 'apply' in request.POST: + form = AddCategoryForm(request.POST) + if form.is_valid(): + category = form.cleaned_data['category'] + + count = 0 + for mediafile in queryset: + category.mediafile_set.add(mediafile) + count += 1 + + message = ungettext('Successfully added %(count)d media file to %(category)s.', + 'Successfully added %(count)d media files to %(category)s.', + count) % {'count':count, 'category':category} + modeladmin.message_user(request, message) + return HttpResponseRedirect(request.get_full_path()) + if 'cancel' in request.POST: + return HttpResponseRedirect(request.get_full_path()) + + if not form: + form = AddCategoryForm(initial={ + '_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME), + }) + + return render_to_response('admin/medialibrary/add_to_category.html', { + 'mediafiles': queryset, + 'category_form': form, + }, context_instance=RequestContext(request)) + +assign_category.short_description = _('Add selected media files to category') + +#------------------------------------------------------------------------- +def save_as_zipfile(modeladmin, request, queryset): + from .zip import export_zipfile + + site = Site.objects.get_current() + try: + zip_name = export_zipfile(site, queryset) + messages.info(request, _("ZIP file exported as %s") % zip_name) + except Exception, e: + messages.error(request, _("ZIP file export failed: %s") % str(e)) + return + + return HttpResponseRedirect(os.path.join(django_settings.MEDIA_URL, zip_name)) + +save_as_zipfile.short_description = _('Export selected media files as zip file') + +# ------------------------------------------------------------------------ +class MediaFileAdmin(admin.ModelAdmin): + save_on_top = True + form = MediaFileAdminForm + date_hierarchy = 'created' + inlines = [admin_translationinline(MediaFileTranslation)] + list_display = ['admin_thumbnail', '__unicode__', 'file_info', 'formatted_created'] + list_display_links = ['__unicode__'] + list_filter = ['type', 'categories'] + list_per_page = 25 + search_fields = ['copyright', 'file', 'translations__caption'] + filter_horizontal = ("categories",) + actions = [assign_category, save_as_zipfile] + + def get_urls(self): + from django.conf.urls.defaults import url, patterns + + urls = super(MediaFileAdmin, self).get_urls() + my_urls = patterns('', + url(r'^mediafile-bulk-upload/$', self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, name='mediafile_bulk_upload') + ) + + return my_urls + urls + + def changelist_view(self, request, extra_context=None): + if extra_context is None: + extra_context = {} + extra_context['categories'] = Category.objects.order_by('title') + return super(MediaFileAdmin, self).changelist_view(request, extra_context=extra_context) + + def admin_thumbnail(self, obj): + if obj.type == 'image': + image = None + try: + image = feincms_thumbnail.thumbnail(obj.file.name, '100x100') + except: + pass + + if image: + return mark_safe(u""" + + + """ % { + 'url': obj.file.url, + 'image': image,}) + return '' + admin_thumbnail.short_description = _('Preview') + admin_thumbnail.allow_tags = True + + def formatted_file_size(self, obj): + return filesizeformat(obj.file_size) + formatted_file_size.short_description = _("file size") + formatted_file_size.admin_order_field = 'file_size' + + def formatted_created(self, obj): + return obj.created.strftime("%Y-%m-%d") + formatted_created.short_description = _("created") + formatted_created.admin_order_field = 'created' + + def file_type(self, obj): + t = obj.filetypes_dict[obj.type] + if obj.type == 'image': + # get_image_dimensions is expensive / slow if the storage is not local filesystem (indicated by availability the path property) + try: + obj.file.path + except NotImplementedError: + return t + try: + d = get_image_dimensions(obj.file.file) + if d: + t += " %d×%d" % ( d[0], d[1] ) + except IOError, e: + t += " (%s)" % e.strerror + return t + file_type.admin_order_field = 'type' + file_type.short_description = _('file type') + file_type.allow_tags = True + + def file_info(self, obj): + """ + Method for showing the file name in admin. + + Note: This also includes a hidden field that can be used to extract + the file name later on, this can be used to access the file name from + JS, like for example a TinyMCE connector shim. + """ + from feincms.utils import shorten_string + return u' %s
%s, %s' % ( + obj.id, + obj.file.name, + obj.id, + shorten_string(os.path.basename(obj.file.name), max_length=40), + self.file_type(obj), + self.formatted_file_size(obj), + ) + file_info.admin_order_field = 'file' + file_info.short_description = _('file info') + file_info.allow_tags = True + + @staticmethod + @csrf_protect + @permission_required('medialibrary.add_mediafile') + def bulk_upload(request): + from .zip import import_zipfile + + if request.method == 'POST' and 'data' in request.FILES: + try: + count = import_zipfile(request.POST.get('category'), request.POST.get('overwrite', False), request.FILES['data']) + messages.info(request, _("%d files imported") % count) + except Exception, e: + messages.error(request, _("ZIP import failed: %s") % str(e)) + else: + messages.error(request, _("No input file given")) + + return HttpResponseRedirect(reverse('admin:medialibrary_mediafile_changelist')) + + def queryset(self, request): + return super(MediaFileAdmin, self).queryset(request).transform(lookup_translations()) + + def save_model(self, request, obj, form, change): + obj.purge_translation_cache() + return super(MediaFileAdmin, self).save_model(request, obj, form, change) + +# ------------------------------------------------------------------------ From 9a9b6dd5abc94bbe39e8e4defce82d025eb9c965 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 21:56:09 +0100 Subject: [PATCH 0232/1590] Move utility method for generating max sized keys to feincms.utils --- feincms/module/page/models.py | 24 +++++++----------------- feincms/utils/__init__.py | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 7e1918b87..d63ce8f4f 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -32,20 +32,7 @@ from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin -# ------------------------------------------------------------------------ -def path_to_cache_key(path): - from django.utils.encoding import iri_to_uri - path = iri_to_uri(path) - - # logic below borrowed from http://richwklein.com/2009/08/04/improving-django-cache-part-ii/ - # via acdha's django-sugar - if len(path) > 200: - m = md5() - m.update(path) - path = m.hexdigest() + '-' + path[:180] - - cache_key = 'FEINCMS:%d:PAGE-FOR-URL:%s' % (django_settings.SITE_ID, path) - return cache_key +from feincms.utils import path_to_cache_key class PageManager(models.Manager, ActiveAwareContentManagerMixin): """ @@ -93,7 +80,7 @@ def best_match_for_path(self, path, raise404=False): # We flush the cache entry on page saving, so the cache should always # be up to date. - ck = path_to_cache_key(path) + ck = Page.path_to_cache_key(path) page = django_cache.get(ck) if page: return page @@ -157,7 +144,6 @@ def for_request(self, request, raise404=False, best_match=False, setup=True): PageManager.add_to_active_filters(Q(active=True)) # ------------------------------------------------------------------------ - class Page(create_base_model(MPTTModel)): active = models.BooleanField(_('active'), default=True) @@ -250,7 +236,7 @@ def save(self, *args, **kwargs): super(Page, self).save(*args, **kwargs) # Okay, we changed the URL -- remove the old stale entry from the cache - ck = path_to_cache_key( self._original_cached_url.strip('/') ) + ck = self.path_to_cache_key(self._original_cached_url) django_cache.delete(ck) # If our cached URL changed we need to update all descendants to @@ -400,9 +386,13 @@ def register_response_processor(cls, fn, key=None): def register_extension(cls, register_fn): register_fn(cls, PageAdmin) + @staticmethod + def path_to_cache_key(path): + return path_to_cache_key(path.strip('/'), prefix="PAGE-FOR-URL") # ------------------------------------------------------------------------ # Our default request processors + Page.register_request_processor(processors.require_path_active_request_processor, key='path_active') Page.register_request_processor(processors.redirect_request_processor, diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index ce3d91128..c6341c1d7 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -2,6 +2,12 @@ # coding=utf-8 # ------------------------------------------------------------------------ +try: + from hashlib import md5 +except ImportError: + import md5 + +from django.conf import settings as django_settings from django.db.models import AutoField from django.utils.importlib import import_module @@ -63,3 +69,24 @@ def shorten_string(str, max_length=50): return str # ------------------------------------------------------------------------ +def path_to_cache_key(path, max_length=200, prefix=""): + """ + Convert a string (path) into something that can be fed to django's + cache mechanism as cache key. Ensure the string stays below the + max key size, so if too long, hash it and use that instead. + """ + + from django.utils.encoding import iri_to_uri + path = iri_to_uri(path) + + # logic below borrowed from http://richwklein.com/2009/08/04/improving-django-cache-part-ii/ + # via acdha's django-sugar + if len(path) > max_length: + m = md5() + m.update(path) + path = m.hexdigest() + '-' + path[:max_length - 20] + + cache_key = 'FEINCMS:%d:%s:%s' % (django_settings.SITE_ID, prefix, path) + return cache_key + +# ------------------------------------------------------------------------ From bbc69a5a27b7d5902b3bb2f93aa098fbcbf53852 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 21:56:51 +0100 Subject: [PATCH 0233/1590] Segregate large Page models.py into models.py, admin.py and modeladmins.py, same structure as MediaFile. --- feincms/module/page/admin.py | 3 +- feincms/module/page/modeladmins.py | 178 +++++++++++++++++++++++++++++ feincms/module/page/models.py | 175 +--------------------------- 3 files changed, 185 insertions(+), 171 deletions(-) create mode 100644 feincms/module/page/modeladmins.py diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index 1c3c82393..e51e517cb 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -6,7 +6,8 @@ from django.contrib import admin -from .models import Page, PageAdmin +from .models import Page +from .modeladmins import PageAdmin # ------------------------------------------------------------------------ admin.site.register(Page, PageAdmin) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py new file mode 100644 index 000000000..b742ae645 --- /dev/null +++ b/feincms/module/page/modeladmins.py @@ -0,0 +1,178 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +from django.core.exceptions import PermissionDenied +from django.contrib.contenttypes.models import ContentType +from django.contrib import admin +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.utils.translation import ugettext_lazy as _ + +from feincms import settings, ensure_completely_loaded +from feincms.admin import item_editor, tree_editor + +# ------------------------------------------------------------------------ +from .forms import PageAdminForm +from .models import Page + +# ------------------------------------------------------------------------ +class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): + class Media: + css = {} + js = [] + + form = PageAdminForm + + # the fieldsets config here is used for the add_view, it has no effect + # for the change_view which is completely customized anyway + unknown_fields = ['template_key', 'parent', 'override_url', 'redirect_to'] + fieldset_insertion_index = 2 + fieldsets = [ + (None, { + 'fields': [ + ('title', 'slug'), + ('active', 'in_navigation'), + ], + }), + (_('Other options'), { + 'classes': ['collapse',], + 'fields': unknown_fields, + }), + # <-- insertion point, extensions appear here, see insertion_index above + item_editor.FEINCMS_CONTENT_FIELDSET, + ] + readonly_fields = [] + list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] + list_filter = ['active', 'in_navigation', 'template_key', 'parent'] + search_fields = ['title', 'slug'] + prepopulated_fields = { 'slug': ('title',), } + + raw_id_fields = ['parent'] + radio_fields = {'template_key': admin.HORIZONTAL} + + @classmethod + def add_extension_options(cls, *f): + if isinstance(f[-1], dict): # called with a fieldset + cls.fieldsets.insert(cls.fieldset_insertion_index, f) + f[1]['classes'] = list(f[1].get('classes', [])) + f[1]['classes'].append('collapse') + else: # assume called with "other" fields + cls.fieldsets[1][1]['fields'].extend(f) + + def __init__(self, *args, **kwargs): + ensure_completely_loaded() + + if len(Page._feincms_templates) > 4 and 'template_key' in self.radio_fields: + del(self.radio_fields['template_key']) + + super(PageAdmin, self).__init__(*args, **kwargs) + + # The use of fieldsets makes only fields explicitly listed in there + # actually appear in the admin form. However, extensions should not be + # aware that there is a fieldsets structure and even less modify it; + # we therefore enumerate all of the model's field and forcibly add them + # to the last section in the admin. That way, nobody is left behind. + from django.contrib.admin.util import flatten_fieldsets + present_fields = flatten_fieldsets(self.fieldsets) + + for f in self.model._meta.fields: + if not f.name.startswith('_') and not f.name in ('id', 'lft', 'rght', 'tree_id', 'level') and \ + not f.auto_created and not f.name in present_fields and f.editable: + self.unknown_fields.append(f.name) + if not f.editable: + self.readonly_fields.append(f.name) + + in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) + + def _actions_column(self, page): + editable = getattr(page, 'feincms_editable', True) + + preview_url = "../../r/%s/%s/" % ( + ContentType.objects.get_for_model(self.model).id, + page.id) + actions = super(PageAdmin, self)._actions_column(page) + if editable: + actions.insert(0, u'%s' % ( + page.pk, _('Add child page'), settings._HACK_ADMIN_MEDIA_IMAGES, _('Add child page'))) + actions.insert(0, u'%s' % ( + preview_url, _('View on site'), settings._HACK_ADMIN_MEDIA_IMAGES, _('View on site'))) + + return actions + + def add_view(self, request, **kwargs): + # Preserve GET parameters + kwargs['form_url'] = request.get_full_path() + return super(PageAdmin, self).add_view(request, **kwargs) + + def response_add(self, request, obj, *args, **kwargs): + response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) + if 'parent' in request.GET and '_addanother' in request.POST and response.status_code in (301, 302): + # Preserve GET parameters if we are about to add another page + response['Location'] += '?parent=%s' % request.GET['parent'] + if 'translation_of' in request.GET: + # Copy all contents + for content_type in obj._feincms_content_types: + if content_type.objects.filter(parent=obj).exists(): + # Short-circuit processing -- don't copy any contents if + # newly added object already has some + return response + + try: + original = self.model._tree_manager.get(pk=request.GET.get('translation_of')) + original = original.original_translation + obj.copy_content_from(original) + obj.save() + + self.message_user(request, _('The content from the original translation has been copied to the newly created page.')) + except (AttributeError, self.model.DoesNotExist): + pass + + return response + + def _refresh_changelist_caches(self, *args, **kwargs): + self._visible_pages = list(self.model.objects.active().values_list('id', flat=True)) + + def change_view(self, request, object_id, **kwargs): + try: + return super(PageAdmin, self).change_view(request, object_id, **kwargs) + except PermissionDenied: + from django.contrib import messages + messages.add_message(request, messages.ERROR, _("You don't have the necessary permissions to edit this object")) + return HttpResponseRedirect(reverse('admin:page_page_changelist')) + + def is_visible_admin(self, page): + """ + Instead of just showing an on/off boolean, also indicate whether this + page is not visible because of publishing dates or inherited status. + """ + if not hasattr(self, "_visible_pages"): + self._visible_pages = list() # Sanity check in case this is not already defined + + if page.parent_id and not page.parent_id in self._visible_pages: + # parent page's invisibility is inherited + if page.id in self._visible_pages: + self._visible_pages.remove(page.id) + return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('inherited')) + + if page.active and not page.id in self._visible_pages: + # is active but should not be shown, so visibility limited by extension: show a "not active" + return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('extensions')) + + return tree_editor.ajax_editable_boolean_cell(page, 'active') + is_visible_admin.allow_tags = True + is_visible_admin.short_description = _('is active') + is_visible_admin.editable_boolean_field = 'active' + + # active toggle needs more sophisticated result function + def is_visible_recursive(self, page): + retval = [] + for c in page.get_descendants(include_self=True): + retval.append(self.is_visible_admin(c)) + return retval + is_visible_admin.editable_boolean_result = is_visible_recursive + +# ------------------------------------------------------------------------ +# ------------------------------------------------------------------------ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index d63ce8f4f..3ec430c4c 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -2,31 +2,20 @@ # coding=utf-8 # ------------------------------------------------------------------------ -try: - from hashlib import md5 -except ImportError: - import md5 - import re -import warnings from django.core.cache import cache as django_cache -from django.core.exceptions import PermissionDenied from django.conf import settings as django_settings -from django.contrib.contenttypes.models import ContentType -from django.contrib import admin -from django.core.urlresolvers import reverse from django.db import models from django.db.models import Q, signals -from django.http import Http404, HttpResponseRedirect +from django.http import Http404 from django.utils.datastructures import SortedDict from django.utils.translation import ugettext_lazy as _ from django.db.transaction import commit_on_success from mptt.models import MPTTModel -from feincms import settings, ensure_completely_loaded -from feincms.admin import item_editor, tree_editor +from feincms import settings from feincms.management.checker import check_database_schema from feincms.models import create_base_model from feincms.module.page import processors @@ -34,6 +23,7 @@ from feincms.utils import path_to_cache_key +# ------------------------------------------------------------------------ class PageManager(models.Manager, ActiveAwareContentManagerMixin): """ The page manager. Only adds new methods, does not modify standard Django @@ -404,164 +394,9 @@ def path_to_cache_key(path): signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) - # ------------------------------------------------------------------------ -from .forms import PageAdminForm - -class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): - class Media: - css = {} - js = [] - - form = PageAdminForm - - # the fieldsets config here is used for the add_view, it has no effect - # for the change_view which is completely customized anyway - unknown_fields = ['template_key', 'parent', 'override_url', 'redirect_to'] - fieldset_insertion_index = 2 - fieldsets = [ - (None, { - 'fields': [ - ('title', 'slug'), - ('active', 'in_navigation'), - ], - }), - (_('Other options'), { - 'classes': ['collapse',], - 'fields': unknown_fields, - }), - # <-- insertion point, extensions appear here, see insertion_index above - item_editor.FEINCMS_CONTENT_FIELDSET, - ] - readonly_fields = [] - list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] - list_filter = ['active', 'in_navigation', 'template_key', 'parent'] - search_fields = ['title', 'slug'] - prepopulated_fields = { 'slug': ('title',), } - - raw_id_fields = ['parent'] - radio_fields = {'template_key': admin.HORIZONTAL} - - @classmethod - def add_extension_options(cls, *f): - if isinstance(f[-1], dict): # called with a fieldset - cls.fieldsets.insert(cls.fieldset_insertion_index, f) - f[1]['classes'] = list(f[1].get('classes', [])) - f[1]['classes'].append('collapse') - else: # assume called with "other" fields - cls.fieldsets[1][1]['fields'].extend(f) - - def __init__(self, *args, **kwargs): - ensure_completely_loaded() - - if len(Page._feincms_templates) > 4 and 'template_key' in self.radio_fields: - del(self.radio_fields['template_key']) - - super(PageAdmin, self).__init__(*args, **kwargs) - - # The use of fieldsets makes only fields explicitly listed in there - # actually appear in the admin form. However, extensions should not be - # aware that there is a fieldsets structure and even less modify it; - # we therefore enumerate all of the model's field and forcibly add them - # to the last section in the admin. That way, nobody is left behind. - from django.contrib.admin.util import flatten_fieldsets - present_fields = flatten_fieldsets(self.fieldsets) - - for f in self.model._meta.fields: - if not f.name.startswith('_') and not f.name in ('id', 'lft', 'rght', 'tree_id', 'level') and \ - not f.auto_created and not f.name in present_fields and f.editable: - self.unknown_fields.append(f.name) - if not f.editable: - self.readonly_fields.append(f.name) - - in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) - - def _actions_column(self, page): - editable = getattr(page, 'feincms_editable', True) - - preview_url = "../../r/%s/%s/" % ( - ContentType.objects.get_for_model(self.model).id, - page.id) - actions = super(PageAdmin, self)._actions_column(page) - if editable: - actions.insert(0, u'%s' % ( - page.pk, _('Add child page'), settings._HACK_ADMIN_MEDIA_IMAGES, _('Add child page'))) - actions.insert(0, u'%s' % ( - preview_url, _('View on site'), settings._HACK_ADMIN_MEDIA_IMAGES, _('View on site'))) - - return actions - - def add_view(self, request, **kwargs): - # Preserve GET parameters - kwargs['form_url'] = request.get_full_path() - return super(PageAdmin, self).add_view(request, **kwargs) - - def response_add(self, request, obj, *args, **kwargs): - response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) - if 'parent' in request.GET and '_addanother' in request.POST and response.status_code in (301, 302): - # Preserve GET parameters if we are about to add another page - response['Location'] += '?parent=%s' % request.GET['parent'] - if 'translation_of' in request.GET: - # Copy all contents - for content_type in obj._feincms_content_types: - if content_type.objects.filter(parent=obj).exists(): - # Short-circuit processing -- don't copy any contents if - # newly added object already has some - return response - - try: - original = self.model._tree_manager.get(pk=request.GET.get('translation_of')) - original = original.original_translation - obj.copy_content_from(original) - obj.save() - - self.message_user(request, _('The content from the original translation has been copied to the newly created page.')) - except (AttributeError, self.model.DoesNotExist): - pass - - return response - - def _refresh_changelist_caches(self, *args, **kwargs): - self._visible_pages = list(self.model.objects.active().values_list('id', flat=True)) - - def change_view(self, request, object_id, **kwargs): - try: - return super(PageAdmin, self).change_view(request, object_id, **kwargs) - except PermissionDenied: - from django.contrib import messages - messages.add_message(request, messages.ERROR, _("You don't have the necessary permissions to edit this object")) - return HttpResponseRedirect(reverse('admin:page_page_changelist')) - - def is_visible_admin(self, page): - """ - Instead of just showing an on/off boolean, also indicate whether this - page is not visible because of publishing dates or inherited status. - """ - if not hasattr(self, "_visible_pages"): - self._visible_pages = list() # Sanity check in case this is not already defined - - if page.parent_id and not page.parent_id in self._visible_pages: - # parent page's invisibility is inherited - if page.id in self._visible_pages: - self._visible_pages.remove(page.id) - return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('inherited')) - - if page.active and not page.id in self._visible_pages: - # is active but should not be shown, so visibility limited by extension: show a "not active" - return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('extensions')) - - return tree_editor.ajax_editable_boolean_cell(page, 'active') - is_visible_admin.allow_tags = True - is_visible_admin.short_description = _('is active') - is_visible_admin.editable_boolean_field = 'active' - - # active toggle needs more sophisticated result function - def is_visible_recursive(self, page): - retval = [] - for c in page.get_descendants(include_self=True): - retval.append(self.is_visible_admin(c)) - return retval - is_visible_admin.editable_boolean_result = is_visible_recursive +# Down here as to avoid circular imports +from .modeladmins import PageAdmin # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ From 07d6033a32ec04e089a720c9bc9df36d4c7d3dcc Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 2 Mar 2012 22:49:29 +0100 Subject: [PATCH 0234/1590] Siblings_along_path: Better fix, avoid doing any work if nothing to work with. --- .../page/templatetags/feincms_page_tags.py | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 0d8dd718b..a029879d1 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -385,34 +385,34 @@ def siblings_along_path_to(page_list, page2): {% endwith %} """ - try: - # Try to avoid hitting the database: If the current page is in_navigation, - # then all relevant pages are already in the incoming list, no need to - # fetch ancestors or children. - - # NOTE: This assumes that the input list actually is complete (ie. comes from - # feincms_navigation). We'll cope with the fall-out of that assumption - # when it happens... - ancestors = [a_page for a_page in page_list - if _is_equal_or_parent_of(a_page, page2)] - top_level = 1 - if page_list: + if page_list: + try: + # Try to avoid hitting the database: If the current page is in_navigation, + # then all relevant pages are already in the incoming list, no need to + # fetch ancestors or children. + + # NOTE: This assumes that the input list actually is complete (ie. comes from + # feincms_navigation). We'll cope with the fall-out of that assumption + # when it happens... + ancestors = [a_page for a_page in page_list + if _is_equal_or_parent_of(a_page, page2)] top_level = min((a_page.level for a_page in page_list)) - if not ancestors: - # Happens when we sit on a page outside the navigation tree - # so fake an active root page to avoid a get_ancestors() db call - # which would only give us a non-navigation root page anyway. - p = Page(title="dummy", tree_id=-1, parent_id=None, in_navigation=False) - ancestors = (p,) - - siblings = [a_page for a_page in page_list - if a_page.parent_id == page2.id or - a_page.level == top_level or - any((_is_sibling_of(a_page, a) for a in ancestors))] - return siblings - except AttributeError: - return () + if not ancestors: + # Happens when we sit on a page outside the navigation tree + # so fake an active root page to avoid a get_ancestors() db call + # which would only give us a non-navigation root page anyway. + p = Page(title="dummy", tree_id=-1, parent_id=None, in_navigation=False) + ancestors = (p,) + + siblings = [a_page for a_page in page_list + if a_page.parent_id == page2.id or + a_page.level == top_level or + any((_is_sibling_of(a_page, a) for a in ancestors))] + return siblings + except AttributeError: + pass -# ------------------------------------------------------------------------ + return () +# ------------------------------------------------------------------------ From 41c31f86395f9f55d02ddfef368ebe32dbb04da6 Mon Sep 17 00:00:00 2001 From: Michael Bashkirov Date: Sun, 4 Mar 2012 00:53:28 +0400 Subject: [PATCH 0235/1590] '_tree_manager' is deprecated in favor of default manager name 'objects' --- feincms/admin/tree_editor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 95a1f529c..59e064480 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -366,19 +366,19 @@ def has_delete_permission(self, request, obj=None): return r and super(TreeEditor, self).has_delete_permission(request, obj) def _move_node(self, request): - cut_item = self.model._tree_manager.get(pk=request.POST.get('cut_item')) - pasted_on = self.model._tree_manager.get(pk=request.POST.get('pasted_on')) + cut_item = self.model.objects.get(pk=request.POST.get('cut_item')) + pasted_on = self.model.objects.get(pk=request.POST.get('pasted_on')) position = request.POST.get('position') if position in ('last-child', 'left'): try: - self.model._tree_manager.move_node(cut_item, pasted_on, position) + self.model.objects.move_node(cut_item, pasted_on, position) except InvalidMove, e: self.message_user(request, unicode(e)) return HttpResponse('FAIL') # Ensure that model save has been run - cut_item = self.model._tree_manager.get(pk=cut_item.pk) + cut_item = self.model.objects.get(pk=cut_item.pk) cut_item.save() self.message_user(request, ugettext('%s has been moved to a new position.') % From 326c7e37d49d01153603dc9327014fad9de49734 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 5 Mar 2012 08:08:50 +0100 Subject: [PATCH 0236/1590] Try being a better citizen by switching to distutils and requirements.txt --- MANIFEST.in | 13 +++------ requirements.txt | 2 ++ setup.py | 76 ++++-------------------------------------------- setuplib.py | 50 +++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 79 deletions(-) create mode 100644 requirements.txt create mode 100644 setuplib.py diff --git a/MANIFEST.in b/MANIFEST.in index 5549b42aa..2b605a533 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,12 +1,7 @@ include AUTHORS include LICENSE +include MANIFEST.in include README.rst -recursive-include feincms/static *.png -recursive-include feincms/static *.jpg -recursive-include feincms/static *.gif -recursive-include feincms/static *.js -recursive-include feincms/static *.css -recursive-include feincms/locale *.po -recursive-include feincms/locale *.mo -recursive-include feincms/templates *.html -recursive-include feincms/templates *.txt +recursive-include feincms/static * +recursive-include feincms/locale * +recursive-include feincms/templates * diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..6f85f5a47 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Django>=1.3 +django-mptt>=0.4 diff --git a/setup.py b/setup.py index 83de4dea6..295a48b6a 100755 --- a/setup.py +++ b/setup.py @@ -1,32 +1,13 @@ #!/usr/bin/env python +from distutils.core import setup import os -from setuptools import setup, find_packages -from setuptools.dist import Distribution -import pkg_resources +import setuplib - -add_django_dependency = True -# See issues #50, #57 and #58 for why this is necessary -try: - pkg_resources.get_distribution('Django') - add_django_dependency = False -except pkg_resources.DistributionNotFound: - try: - import django - if django.VERSION[0] >= 1 and django.VERSION[1] >= 3 and django.VERSION[2] >= 0: - add_django_dependency = False - except ImportError: - pass - -Distribution({ - "setup_requires": add_django_dependency and ['Django >=1.3.0'] or [] -}) - -import feincms +packages, data_files = setuplib.find_files('feincms') setup(name='FeinCMS', - version=feincms.__version__, + version=__import__('feincms').__version__, description='Django-based Page CMS and CMS building toolkit.', long_description=open(os.path.join(os.path.dirname(__file__), 'README.rst')).read(), author='Matthias Kestenholz', @@ -34,6 +15,8 @@ url='http://github.com/feincms/feincms/', license='BSD License', platforms=['OS Independent'], + packages=packages, + data_files=data_files, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', @@ -46,51 +29,4 @@ 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Application Frameworks', ], - install_requires=[ - #'Django >=1.3.0' # See http://github.com/feincms/feincms/issues/closed#issue/50 - ], - requires=[ - #'lxml', # only needed for rich text cleansing - #'tagging (>0.2.1)', # please use SVN trunk - 'django_mptt (>0.4.0)', - ], - packages=[ - 'feincms', - 'feincms.admin', - 'feincms.content', - 'feincms.content.application', - 'feincms.content.comments', - 'feincms.content.contactform', - 'feincms.content.file', - 'feincms.content.image', - 'feincms.content.medialibrary', - 'feincms.content.raw', - 'feincms.content.richtext', - 'feincms.content.rss', - 'feincms.content.section', - 'feincms.content.table', - 'feincms.content.template', - 'feincms.content.video', - 'feincms.contrib', - 'feincms.contrib.preview', - 'feincms.management', - 'feincms.management.commands', - 'feincms.module', - 'feincms.module.blog', - 'feincms.module.blog.extensions', - 'feincms.module.medialibrary', - 'feincms.module.extensions', - 'feincms.module.page', - 'feincms.module.page.extensions', - 'feincms.module.page.templatetags', - 'feincms.templatetags', - 'feincms.utils', - 'feincms.utils.html', - 'feincms.views', - 'feincms.views.cbv', - 'feincms.views.generic', - 'feincms.views.legacy', - ], - include_package_data=True, - zip_safe=False, ) diff --git a/setuplib.py b/setuplib.py new file mode 100644 index 000000000..a95f8586f --- /dev/null +++ b/setuplib.py @@ -0,0 +1,50 @@ +import os + + +__all__ = ['find_files'] + + +def fullsplit(path, result=None): + """ + Split a pathname into components (the opposite of os.path.join) in a + platform-neutral way. + """ + if result is None: + result = [] + head, tail = os.path.split(path) + if head == '': + return [tail] + result + if head == path: + return result + return fullsplit(head, [tail] + result) + + +def find_files(package_dir): + """ + Returns a tuple consisting of a list of packages and a list of data + files suitable for passing on to ``distutils.core.setup`` + + Requires the folder name containing the package files; ``find_files`` + assumes that ``setup.py`` is located in the same folder as the folder + containing those files. + + Code lifted from Django's ``setup.py``, thanks! + """ + + # Compile the list of packages available, because distutils doesn't have + # an easy way to do this. + packages, data_files = [], [] + root_dir = os.path.dirname(__file__) + if root_dir != '': + os.chdir(root_dir) + + for dirpath, dirnames, filenames in os.walk(package_dir): + # Ignore dirnames that start with '.' + for i, dirname in enumerate(dirnames): + if dirname.startswith('.'): del dirnames[i] + if '__init__.py' in filenames: + packages.append('.'.join(fullsplit(dirpath))) + elif filenames: + data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) + + return packages, data_files From 3714e4d06316678d9da7a93956c493da69ec7508 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 6 Mar 2012 11:12:18 +0100 Subject: [PATCH 0237/1590] Add logging to medialibrary. --- feincms/module/medialibrary/models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 07ecb1cbb..bc8952dc3 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -23,6 +23,8 @@ from feincms.models import ExtensionsMixin from feincms.translations import TranslatedObjectMixin, Translation, TranslatedObjectManager +logger = logging.getLogger('feincms.medialibrary') + # ------------------------------------------------------------------------ class CategoryManager(models.Manager): """ @@ -174,7 +176,7 @@ def save(self, *args, **kwargs): try: self.file_size = self.file.size except (OSError, IOError, ValueError), e: - logging.error("Unable to read file size for %s: %s", self, e) + logger.error("Unable to read file size for %s: %s" % (self, e)) # Try to detect things that are not really images if self.type == 'image': @@ -212,7 +214,10 @@ def save(self, *args, **kwargs): if getattr(self, '_original_file_name', None): if self.file.name != self._original_file_name: - self.file.storage.delete(self._original_file_name) + try: + self.file.storage.delete(self._original_file_name) + except Exception, e: + logger.error("Cannot delete orphaned file %s: %s" % (self._original_file_name, e)) super(MediaFileBase, self).save(*args, **kwargs) self.purge_translation_cache() From b2e090dfc9530a6520d4c1ac4ce6e9b58c15b167 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 6 Mar 2012 11:14:18 +0100 Subject: [PATCH 0238/1590] Cleanup mediafile saving: Do not auto-rotate the images, that is not a library's job (also, it seems it does not play well with external storage engines, see issue #254). --- feincms/module/medialibrary/models.py | 44 ++++++++------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index bc8952dc3..985de22e0 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -181,37 +181,20 @@ def save(self, *args, **kwargs): # Try to detect things that are not really images if self.type == 'image': try: - try: - image = Image.open(self.file) - except (OSError, IOError): - image = Image.open(self.file.path) - - # Rotate image based on exif data. - if image: - try: - exif = image._getexif() - except (AttributeError, IOError): - exif = False - # PIL < 1.1.7 chokes on JPEGs with minimal EXIF data and - # throws a KeyError deep in its guts. - except KeyError: - exif = False - - if exif: - orientation = exif.get(274) - rotation = 0 - if orientation == 3: - rotation = 180 - elif orientation == 6: - rotation = 270 - elif orientation == 8: - rotation = 90 - if rotation: - image = image.rotate(rotation) - image.save(self.file.path) - except (OSError, IOError), e: - self.type = self.determine_file_type('***') # It's binary something + Image.open(self.file) + # Not an image? PIL raises "IOError: cannot identify image file" + # Note: it also raises that exception for any real I/O error *sigh* + except IOError, e: + if not e.errno: # Not a real IOError but PIL-generated + self.type = self.determine_file_type('***') # It's binary something + logger.warning("Uploaded file %s cannot be opened by PIL: %s" % (self.file.name, e)) + + super(MediaFileBase, self).save(*args, **kwargs) + logger.info("Saved mediafile %d (%s, type %s, %d bytes)" % (self.id, self.file.name, self.type, self.file_size)) + + # User uploaded a new file. Try to get rid of the old file in + # storage, to avoid having orphaned files hanging around. if getattr(self, '_original_file_name', None): if self.file.name != self._original_file_name: try: @@ -219,7 +202,6 @@ def save(self, *args, **kwargs): except Exception, e: logger.error("Cannot delete orphaned file %s: %s" % (self._original_file_name, e)) - super(MediaFileBase, self).save(*args, **kwargs) self.purge_translation_cache() # ------------------------------------------------------------------------ From 25522316cda07eac64db269a1ab7d4aa4bbac3bd Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 6 Mar 2012 11:18:13 +0100 Subject: [PATCH 0239/1590] Add note to release notes about removal of mediafile image auto-rotate. --- docs/releases/1.6.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/releases/1.6.rst b/docs/releases/1.6.rst index 93e245cae..2b8bb70ac 100644 --- a/docs/releases/1.6.rst +++ b/docs/releases/1.6.rst @@ -65,3 +65,9 @@ FeinCMS 1.6 release notes (upcoming) * ``FileContent`` now displays the size of the file in the default template, and uses ``span`` elements to allow styling of the title / size. + +* ``MediaFile`` does no longer auto-rotate images on upload. It really is not a + media library's job to magically modify user content; if needed, it should be + done in an image filter (like sorl). Also, reading through the image data + seems to have a side effect on some external storage engines which then would + only save half the image data, see issue #254. From d0c429cff7861ba9b27a33036ba10c7127649b14 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 6 Mar 2012 13:41:22 +0100 Subject: [PATCH 0240/1590] Centralise logger instanciation. --- feincms/module/medialibrary/__init__.py | 12 ++++++++++++ feincms/module/medialibrary/forms.py | 1 + feincms/module/medialibrary/models.py | 5 ++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/feincms/module/medialibrary/__init__.py b/feincms/module/medialibrary/__init__.py index e69de29bb..fc7e02a00 100644 --- a/feincms/module/medialibrary/__init__.py +++ b/feincms/module/medialibrary/__init__.py @@ -0,0 +1,12 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +import logging + +# ------------------------------------------------------------------------ +logger = logging.getLogger('feincms.medialibrary') + +# ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 8f47be651..8094ec533 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -10,6 +10,7 @@ from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from . import logger from .models import MediaFile # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 985de22e0..699238231 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -5,7 +5,6 @@ from __future__ import absolute_import from datetime import datetime -import logging import os import re @@ -23,7 +22,7 @@ from feincms.models import ExtensionsMixin from feincms.translations import TranslatedObjectMixin, Translation, TranslatedObjectManager -logger = logging.getLogger('feincms.medialibrary') +from . import logger # ------------------------------------------------------------------------ class CategoryManager(models.Manager): @@ -185,9 +184,9 @@ def save(self, *args, **kwargs): # Not an image? PIL raises "IOError: cannot identify image file" # Note: it also raises that exception for any real I/O error *sigh* except IOError, e: + logger.warning("Uploaded file %s cannot be opened by PIL: %s" % (self.file.name, e)) if not e.errno: # Not a real IOError but PIL-generated self.type = self.determine_file_type('***') # It's binary something - logger.warning("Uploaded file %s cannot be opened by PIL: %s" % (self.file.name, e)) super(MediaFileBase, self).save(*args, **kwargs) From f4650288347f6cd800e347e5aeda643f17d5d6b6 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 6 Mar 2012 13:42:19 +0100 Subject: [PATCH 0241/1590] feincms_thumbnail: Wrap everything in a try/except block since PIL might throw an error later on (eg. on truncated files). --- feincms/templatetags/feincms_thumbnail.py | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 8e9eddbf3..c8a5a58ca 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -87,29 +87,29 @@ def __unicode__(self): def generate(self, storage, original, size, miniature): try: image = Image.open(StringIO(storage.open(original).read())) + + # defining the size + w, h = int(size['w']), int(size['h']) + + format = image.format # Save format for the save() call later + image.thumbnail([w, h], Image.ANTIALIAS) + buf = StringIO() + if image.mode not in ('RGBA', 'RGB', 'L'): + image = image.convert('RGBA') + image.save(buf, format or 'jpeg', quality=80) + raw_data = buf.getvalue() + buf.close() + + storage.delete(miniature) + storage.save(miniature, ContentFile(raw_data)) + + return storage.url(miniature) except: # PIL raises a plethora of Exceptions if reading the image # is not possible. Since we cannot be sure what Exception will # happen, catch them all so the thumbnailer will never fail. return storage.url(original) - storage.delete(miniature) - - # defining the size - w, h = int(size['w']), int(size['h']) - - format = image.format # Save format for the save() call later - image.thumbnail([w, h], Image.ANTIALIAS) - buf = StringIO() - if image.mode not in ('RGBA', 'RGB', 'L'): - image = image.convert('RGBA') - image.save(buf, format or 'jpeg', quality=100) - raw_data = buf.getvalue() - buf.close() - storage.save(miniature, ContentFile(raw_data)) - - return storage.url(miniature) - class CropscaleThumbnailer(Thumbnailer): THUMBNAIL_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)(-(?P\d+)x(?P\d+))?$') From d05f8eecdaaf335f9b406db4bd2a11e94e6d8928 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 6 Mar 2012 13:44:14 +0100 Subject: [PATCH 0242/1590] Totally rework the FEINCMS_MEDIAFILE_OVERWRITE. This suffered from sticky file names (ie. you uploaded one file, then another over the first, then a third, and the third would overwrite the first file. This is caused by the field being instanciated once). --- feincms/module/medialibrary/forms.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 8094ec533..8e05ff53d 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -21,21 +21,30 @@ class Meta: def __init__(self, *args, **kwargs): super(MediaFileAdminForm, self).__init__(*args, **kwargs) if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: - self.original_name = self.instance.file.name + if not hasattr(self.instance.file.field, '_feincms_generate_filename_patched'): + orig_generate_filename = self.instance.file.field.generate_filename - def gen_fname(instance, filename): - self.instance.file.storage.delete(self.original_name) - return self.original_name - self.instance.file.field.generate_filename = gen_fname + def _gen_fname(instance, filename): + if instance.id and hasattr(instance, 'original_name'): + logger.info("Overwriting file %s with new data" % instance.original_name) + instance.file.storage.delete(instance.original_name) + return instance.original_name + + return orig_generate_filename(instance, filename) + + self.instance.file.field.generate_filename = _gen_fname + self.instance.file.field._feincms_generate_filename_patched = True def clean_file(self): - if settings.FEINCMS_MEDIAFILE_OVERWRITE and hasattr(self, 'original_name'): + if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: new_base, new_ext = os.path.splitext(self.cleaned_data['file'].name) - old_base, old_ext = os.path.splitext(self.original_name) + old_base, old_ext = os.path.splitext(self.instance.file.name) if new_ext.lower() != old_ext.lower(): raise forms.ValidationError(_("Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)") % { 'old_ext': old_ext, 'new_ext': new_ext }) + self.instance.original_name = self.instance.file.name + return self.cleaned_data['file'] # ------------------------------------------------------------------------ From 444fb93b0b27e5f370acfba2c69500655acd24a8 Mon Sep 17 00:00:00 2001 From: Michael Bashkirov Date: Wed, 7 Mar 2012 15:16:29 +0400 Subject: [PATCH 0243/1590] Fall back to the old tree manager location if move_node doesn't exist. --- feincms/admin/tree_editor.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 59e064480..c65915738 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -366,13 +366,18 @@ def has_delete_permission(self, request, obj=None): return r and super(TreeEditor, self).has_delete_permission(request, obj) def _move_node(self, request): - cut_item = self.model.objects.get(pk=request.POST.get('cut_item')) - pasted_on = self.model.objects.get(pk=request.POST.get('pasted_on')) + if hasattr(self.model.objects, 'move_node'): + tree_manager = self.model.objects + else: + tree_manager = self.model._tree_manager + + cut_item = tree_manager.get(pk=request.POST.get('cut_item')) + pasted_on = tree_manager.get(pk=request.POST.get('pasted_on')) position = request.POST.get('position') if position in ('last-child', 'left'): try: - self.model.objects.move_node(cut_item, pasted_on, position) + tree_manager.move_node(cut_item, pasted_on, position) except InvalidMove, e: self.message_user(request, unicode(e)) return HttpResponse('FAIL') From 4261dcd28c7cc0ee4d96f3e2e7d7005443791ec5 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 7 Mar 2012 14:29:23 +0100 Subject: [PATCH 0244/1590] Use the correct settings to pick up our default values. --- feincms/module/medialibrary/forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 8e05ff53d..2da9dd8ab 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -7,9 +7,10 @@ import os from django import forms -from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from feincms import settings + from . import logger from .models import MediaFile From a142d8af60e380e292118070824debf579859043 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 8 Mar 2012 12:55:07 +0100 Subject: [PATCH 0245/1590] Documentation: Add missing trailing comma for tuple in example. --- docs/contenttypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 741d140e4..3708b2057 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -205,7 +205,7 @@ media files they need:: def media(self): return forms.Media( css={'all': ('gallery/gallery.css',),}, - js=('gallery/gallery.js'), + js=('gallery/gallery.js',), ) def render(self, **kwargs): From 90bb112d05b2db7ce9fdd33a8637a5eed75fec70 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 8 Mar 2012 13:30:11 +0100 Subject: [PATCH 0246/1590] Add a note how to implement a Media inner class in own content types. --- docs/contenttypes.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 3708b2057..4c4c5164e 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -219,6 +219,18 @@ provide the ``media`` property yourself. As with form and widget media definitio either ``STATIC_URL`` or ``MEDIA_URL`` (in this order) will be prepended to the media file path if it is not an absolute path already. +Alternatively, you can use the ``media_property`` function from django.forms +to implement the functionality, which then also supports inheritance +of media files:: + + from django.forms.widgets import media_property + + class MediaUsingContentType(models.Model): + class Media: + js = ('whizbang.js',) + + MediaUsingContentType.media = media_property(MediaUsingContentType) + .. _contenttypes-processfinalize: From b080bad96c8e990e445df226fca135c3e7d0535c Mon Sep 17 00:00:00 2001 From: Marc Egli Date: Thu, 8 Mar 2012 14:47:19 +0100 Subject: [PATCH 0247/1590] fix the app_reverse templatetag to work in the following situation {% app_reverse "url_name" "myapp.urls" as my_url_var %} --- feincms/templatetags/applicationcontent_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index f62b17a1f..a5a7403f1 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -103,7 +103,7 @@ def app_reverse(parser, token): kwargs = {} asvar = None bits = bits[3:] - if len(bits) >= 3 and bits[-2] == 'as': + if len(bits) >= 2 and bits[-2] == 'as': asvar = bits[-1] bits = bits[:-2] From a0f6699b37365ef27c5bc2d3d5bf5bd150c8e4af Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 9 Mar 2012 16:40:27 +0100 Subject: [PATCH 0248/1590] MediaFile Category Admin: Add validation to "parent" field so one cannot create loops. --- feincms/module/medialibrary/forms.py | 14 +++++++++++++- feincms/module/medialibrary/modeladmins.py | 7 +++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 2da9dd8ab..b39c5f35e 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -12,7 +12,19 @@ from feincms import settings from . import logger -from .models import MediaFile +from .models import Category, MediaFile + +# ------------------------------------------------------------------------ +class MediaCategoryAdminForm(forms.ModelForm): + class Meta: + model = Category + + def clean_parent(self): + data = self.cleaned_data['parent'] + if data is not None and self.instance in data.path_list(): + raise forms.ValidationError(_("This would create a loop in the hierarchy")) + + return data # ------------------------------------------------------------------------ class MediaFileAdminForm(forms.ModelForm): diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 95d055fca..142fa4b94 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -26,10 +26,12 @@ from ...translations import admin_translationinline, lookup_translations from .models import Category, MediaFileTranslation -from .forms import MediaFileAdminForm +from .forms import MediaCategoryAdminForm, MediaFileAdminForm # ----------------------------------------------------------------------- class CategoryAdmin(admin.ModelAdmin): + form = MediaCategoryAdminForm + list_display = ['path'] list_filter = ['parent'] list_per_page = 25 @@ -91,8 +93,9 @@ def save_as_zipfile(modeladmin, request, queryset): # ------------------------------------------------------------------------ class MediaFileAdmin(admin.ModelAdmin): - save_on_top = True form = MediaFileAdminForm + + save_on_top = True date_hierarchy = 'created' inlines = [admin_translationinline(MediaFileTranslation)] list_display = ['admin_thumbnail', '__unicode__', 'file_info', 'formatted_created'] From a60a6b81ab2b86f85c31248305f3a4183f16e1a3 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 9 Mar 2012 16:47:41 +0100 Subject: [PATCH 0249/1590] Update translations. --- feincms/locale/de/LC_MESSAGES/django.po | 328 +++++++++--------- feincms/locale/en/LC_MESSAGES/django.po | 433 +++++++++++++----------- 2 files changed, 420 insertions(+), 341 deletions(-) diff --git a/feincms/locale/de/LC_MESSAGES/django.po b/feincms/locale/de/LC_MESSAGES/django.po index e9f7c3dae..237b3e6c9 100644 --- a/feincms/locale/de/LC_MESSAGES/django.po +++ b/feincms/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-12-27 17:04+0100\n" +"POT-Creation-Date: 2012-03-09 16:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -34,11 +34,12 @@ msgstr "Sprache" msgid "All" msgstr "Alle" -#: admin/filterspecs.py:57 module/page/models.py:222 +#: admin/filterspecs.py:57 module/page/models.py:143 msgid "Parent" msgstr "Übergeordnet" #: admin/filterspecs.py:95 +#: templates/admin/medialibrary/mediafile/change_list.html:15 msgid "Category" msgstr "Kategorie" @@ -49,33 +50,33 @@ msgstr "%s ändern" #: admin/tree_editor.py:214 content/rss/models.py:20 #: content/section/models.py:31 module/blog/models.py:30 -#: module/medialibrary/models.py:51 module/page/models.py:220 -#: module/page/models.py:299 +#: module/medialibrary/models.py:43 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "Titel" -#: admin/tree_editor.py:384 +#: admin/tree_editor.py:389 #, python-format msgid "%s has been moved to a new position." msgstr "%s wurde an eine neue Position verschoben." -#: admin/tree_editor.py:388 +#: admin/tree_editor.py:393 msgid "Did not understand moving instruction." msgstr "Unbekannter Verschiebe-Befehl." -#: admin/tree_editor.py:397 +#: admin/tree_editor.py:402 msgid "actions" msgstr "Aktionen" -#: content/application/models.py:252 +#: content/application/models.py:264 msgid "application content" msgstr "Applikation" -#: content/application/models.py:253 +#: content/application/models.py:265 msgid "application contents" msgstr "Applikationen" -#: content/application/models.py:284 +#: content/application/models.py:296 msgid "application" msgstr "Applikation" @@ -123,28 +124,44 @@ msgstr "Kontaktformular" msgid "contact forms" msgstr "Kontaktformulare" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:101 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:86 msgid "file" msgstr "Datei" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "Dateien" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "Bild" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "Textalternative" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "Beschreibung des Bildes" + +#: content/image/models.py:48 module/medialibrary/models.py:237 +msgid "caption" +msgstr "Legende" + +#: content/image/models.py:53 msgid "images" msgstr "Bilder" -#: content/image/models.py:42 content/medialibrary/models.py:105 +#: content/image/models.py:79 content/medialibrary/models.py:105 #: content/medialibrary/models.py:113 msgid "position" msgstr "Position" +#: content/image/models.py:87 +msgid "format" +msgstr "Format" + #: content/medialibrary/models.py:38 msgid "(no caption)" msgstr "(Keine Legende)" @@ -152,12 +169,12 @@ msgstr "(Keine Legende)" #: content/medialibrary/models.py:87 content/medialibrary/models.py:101 #: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 #: content/section/models.py:47 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:114 +#: module/medialibrary/models.py:99 msgid "media file" msgstr "Mediendatei" #: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:115 +#: module/medialibrary/models.py:100 msgid "media files" msgstr "Mediendateien" @@ -351,7 +368,7 @@ msgid "Leave this empty for entries in the primary language." msgstr "Dieses Feld für Einträge in der Primärsprache leer lassen." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:40 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "Verfügbare Übersetzungen" @@ -427,170 +444,215 @@ msgstr "Übersetzung erstellen" msgid "translations" msgstr "Übersetzungen" -#: module/medialibrary/models.py:54 +#: module/medialibrary/forms.py:25 +msgid "This would create a loop in the hierarchy" +msgstr "Dies würde eine Schleife in der Hierarchie erzeugen" + +#: module/medialibrary/forms.py:57 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" +"Kann nur gleiche Dateitypen ersetzen (versuchte ein %(old_ext)s mit einem " +"%(new_ext)s zu überschreiben)" + +#: module/medialibrary/modeladmins.py:58 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "%(count)d Mediendatei zu %(category)s hinzugefügt." +msgstr[1] "%(count)d Mediendateien zu %(category)s hinzugefügt." + +#: module/medialibrary/modeladmins.py:76 +msgid "Add selected media files to category" +msgstr "Ausgewählte zu Kategorie hinzufügen" + +#: module/medialibrary/modeladmins.py:85 +#, python-format +msgid "ZIP file exported as %s" +msgstr "ZIP-Datei exportiert als %s" + +#: module/medialibrary/modeladmins.py:87 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "ZIP-Datei Export fehlgeschlagen: %s" + +#: module/medialibrary/modeladmins.py:92 +msgid "Export selected media files as zip file" +msgstr "Ausgewählte Mediendateien als ZIP exportieren" + +#: module/medialibrary/modeladmins.py:141 +#: templates/admin/feincms/page/page/item_editor.html:14 +msgid "Preview" +msgstr "Vorschau" + +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:90 +msgid "file size" +msgstr "Dateigrösse" + +#: module/medialibrary/modeladmins.py:151 module/medialibrary/models.py:88 +msgid "created" +msgstr "Erstellt" + +#: module/medialibrary/modeladmins.py:170 module/medialibrary/models.py:87 +msgid "file type" +msgstr "Dateityp" + +#: module/medialibrary/modeladmins.py:191 +msgid "file info" +msgstr "Dateiinfo" + +#: module/medialibrary/modeladmins.py:203 +#, python-format +msgid "%d files imported" +msgstr "%d Dateien importiert" + +#: module/medialibrary/modeladmins.py:205 +#, python-format +msgid "ZIP import failed: %s" +msgstr "ZIP-Import schlug fehl: %s" + +#: module/medialibrary/modeladmins.py:207 +msgid "No input file given" +msgstr "Keine Datei angegeben" + +#: module/medialibrary/models.py:46 msgid "parent" msgstr "Übergeordnet" -#: module/medialibrary/models.py:56 module/page/models.py:221 +#: module/medialibrary/models.py:48 module/page/models.py:142 msgid "slug" msgstr "Slug" -#: module/medialibrary/models.py:60 +#: module/medialibrary/models.py:52 msgid "category" msgstr "Kategorie" -#: module/medialibrary/models.py:61 module/medialibrary/models.py:107 +#: module/medialibrary/models.py:53 module/medialibrary/models.py:92 msgid "categories" msgstr "Kategorien" -#: module/medialibrary/models.py:102 module/medialibrary/models.py:191 -msgid "file type" -msgstr "Dateityp" - -#: module/medialibrary/models.py:103 module/medialibrary/models.py:129 -msgid "created" -msgstr "Erstellt" - -#: module/medialibrary/models.py:104 +#: module/medialibrary/models.py:89 msgid "copyright" msgstr "Copyright" -#: module/medialibrary/models.py:105 module/medialibrary/models.py:124 -msgid "file size" -msgstr "Dateigrösse" - -#: module/medialibrary/models.py:213 -msgid "file info" -msgstr "Dateiinfo" - -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:209 msgid "Image" msgstr "Bild" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:210 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:292 +#: module/medialibrary/models.py:211 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:293 +#: module/medialibrary/models.py:212 msgid "PDF document" msgstr "PDF-Dokument" -#: module/medialibrary/models.py:294 +#: module/medialibrary/models.py:213 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:295 +#: module/medialibrary/models.py:214 msgid "Text" msgstr "Text" -#: module/medialibrary/models.py:296 +#: module/medialibrary/models.py:215 msgid "Rich Text" msgstr "Text" -#: module/medialibrary/models.py:297 +#: module/medialibrary/models.py:216 msgid "Zip archive" msgstr "ZIP-Archiv" -#: module/medialibrary/models.py:298 +#: module/medialibrary/models.py:217 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:299 +#: module/medialibrary/models.py:218 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:300 +#: module/medialibrary/models.py:219 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:301 +#: module/medialibrary/models.py:220 msgid "Binary" msgstr "Binärdaten" -#: module/medialibrary/models.py:317 -msgid "caption" -msgstr "Legende" - -#: module/medialibrary/models.py:318 +#: module/medialibrary/models.py:238 msgid "description" msgstr "Beschreibung" -#: module/medialibrary/models.py:321 +#: module/medialibrary/models.py:241 msgid "media file translation" msgstr "Mediendatei-Übersetzung" -#: module/medialibrary/models.py:322 +#: module/medialibrary/models.py:242 msgid "media file translations" msgstr "Mediendatei-Übersetzungen" -#: module/medialibrary/models.py:345 -#: templates/admin/feincms/page/page/item_editor.html:14 -msgid "Preview" -msgstr "Vorschau" +#: module/page/forms.py:113 +msgid "This URL is already taken by an active page." +msgstr "Die URL wird schon von einer aktiven Seite verwendet." -#: module/medialibrary/models.py:365 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "%(count)d Mediendatei zu %(category)s hinzugefügt." -msgstr[1] "%(count)d Mediendateien zu %(category)s hinzugefügt." +#: module/page/forms.py:131 +msgid "This URL is already taken by another active page." +msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." -#: module/medialibrary/models.py:383 -msgid "Add selected media files to category" -msgstr "Ausgewählte zu Kategorie hinzufügen" +#: module/page/modeladmins.py:40 +msgid "Other options" +msgstr "Weitere Optionen" -#: module/medialibrary/models.py:406 -#, python-format -msgid "" -"Cannot overwrite with different file type (attempt to overwrite a " -"%(old_ext)s with a %(new_ext)s)" -msgstr "Kann nur gleiche Dateitypen ersetzen (versuchte ein %(old_ext)s mit einem %(new_ext)s zu überschreiben)" +#: module/page/modeladmins.py:88 module/page/models.py:145 +msgid "in navigation" +msgstr "Im Menü" -#: module/medialibrary/models.py:394 -#, python-format -msgid "ZIP file exported as %s" -msgstr "ZIP-Datei exportiert als %s" +#: module/page/modeladmins.py:99 +msgid "Add child page" +msgstr "Unterseite hinzufügen" -#: module/medialibrary/models.py:396 -#, python-format -msgid "ZIP file export failed: %s" -msgstr "ZIP-Datei Export fehlgeschlagen: %s" +#: module/page/modeladmins.py:101 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Auf der Webseite anzeigen" -#: module/medialibrary/models.py:400 -msgid "Export selected media files as zip file" -msgstr "Ausgewählte Mediendateien als ZIP exportieren" +#: module/page/modeladmins.py:129 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." +msgstr "" -#: module/medialibrary/models.py:482 -#, python-format -msgid "%d files imported" -msgstr "%d Dateien importiert" +#: module/page/modeladmins.py:143 +msgid "You don't have the necessary permissions to edit this object" +msgstr "Ungenügende Berechtigung um dieses Objekt zu bearbeiten" -#: module/medialibrary/models.py:484 -#, python-format -msgid "ZIP import failed: %s" -msgstr "ZIP-Import schlug fehl: %s" +#: module/page/modeladmins.py:158 +msgid "inherited" +msgstr "geerbt" -#: module/medialibrary/models.py:490 -msgid "No input file given" -msgstr "Keine Datei angegeben" +#: module/page/modeladmins.py:162 +msgid "extensions" +msgstr "Erweiterungen" -#: module/page/models.py:217 -msgid "active" +#: module/page/modeladmins.py:166 module/page/models.py:179 +msgid "is active" msgstr "Aktiv" -#: module/page/models.py:224 module/page/models.py:729 -msgid "in navigation" -msgstr "Im Menü" +#: module/page/models.py:138 +msgid "active" +msgstr "Aktiv" -#: module/page/models.py:225 +#: module/page/models.py:146 msgid "override URL" msgstr "Überschriebene URL" -#: module/page/models.py:226 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -600,62 +662,26 @@ msgstr "" "eine lokale URL handelt. Dieses Feld bestimmt die Navigation und die URLs " "von Unterseiten." -#: module/page/models.py:227 +#: module/page/models.py:148 msgid "redirect to" msgstr "Weiterleiten zu" -#: module/page/models.py:228 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "Ziel-URL für automatische Weiterleitungen." -#: module/page/models.py:229 +#: module/page/models.py:150 msgid "Cached URL" msgstr "Zwischengespeicherte URL" -#: module/page/models.py:240 +#: module/page/models.py:161 msgid "page" msgstr "Seite" -#: module/page/models.py:241 +#: module/page/models.py:162 msgid "pages" msgstr "Seiten" -#: module/page/models.py:258 module/page/models.py:801 -msgid "is active" -msgstr "Aktiv" - -#: module/page/models.py:639 -msgid "This URL is already taken by an active page." -msgstr "Die URL wird schon von einer aktiven Seite verwendet." - -#: module/page/models.py:657 -msgid "This URL is already taken by another active page." -msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." - -#: module/page/models.py:681 -msgid "Other options" -msgstr "Weitere Optionen" - -#: module/page/models.py:740 -msgid "Add child page" -msgstr "Unterseite hinzufügen" - -#: module/page/models.py:742 templates/admin/feincms/content_inline.html:9 -msgid "View on site" -msgstr "Auf der Webseite anzeigen" - -#: module/page/models.py:778 -msgid "You don't have the necessary permissions to edit this object" -msgstr "Ungenügende Berechtigung um dieses Objekt zu bearbeiten" - -#: module/page/models.py:793 -msgid "inherited" -msgstr "geerbt" - -#: module/page/models.py:797 -msgid "extensions" -msgstr "Erweiterungen" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "Auszug" @@ -863,7 +889,7 @@ msgstr "Gelöschtes Element %(verbose_name)s wiederherstellen" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Diese Version kann durch Drücken des Speichern-Knopfes wiederhergestellt werden" #: templates/admin/feincms/revision_form.html:14 msgid "History" @@ -876,7 +902,7 @@ msgstr "Alte Version von %(verbose_name)s wiederherstellen" #: templates/admin/feincms/revision_form.html:28 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Diese Version kann durch Drücken des Speichern-Knopfes zurückgeholt werden" #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -932,7 +958,7 @@ msgstr "Massenupload mit ZIP Dateien:" msgid "Overwrite" msgstr "Überschreiben" -#: templates/admin/medialibrary/mediafile/change_list.html:21 +#: templates/admin/medialibrary/mediafile/change_list.html:25 msgid "Send" msgstr "Senden" diff --git a/feincms/locale/en/LC_MESSAGES/django.po b/feincms/locale/en/LC_MESSAGES/django.po index a7e1462c7..bc17380f6 100644 --- a/feincms/locale/en/LC_MESSAGES/django.po +++ b/feincms/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-15 13:37+0200\n" +"POT-Creation-Date: 2012-03-09 16:47+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,16 +17,16 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:419 content/template/models.py:59 msgid "template" msgstr "" -#: models.py:553 +#: models.py:550 msgid "ordering" msgstr "" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:102 msgid "language" msgstr "" @@ -34,48 +34,49 @@ msgstr "" msgid "All" msgstr "" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:57 module/page/models.py:143 msgid "Parent" msgstr "" #: admin/filterspecs.py:95 +#: templates/admin/medialibrary/mediafile/change_list.html:15 msgid "Category" msgstr "" -#: admin/item_editor.py:152 +#: admin/item_editor.py:163 #, python-format msgid "Change %s" msgstr "" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:258 -#: module/page/models.py:338 +#: admin/tree_editor.py:214 content/rss/models.py:20 +#: content/section/models.py:31 module/blog/models.py:30 +#: module/medialibrary/models.py:43 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:389 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:393 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:402 msgid "actions" msgstr "" -#: content/application/models.py:190 +#: content/application/models.py:264 msgid "application content" msgstr "" -#: content/application/models.py:191 +#: content/application/models.py:265 msgid "application contents" msgstr "" -#: content/application/models.py:222 +#: content/application/models.py:296 msgid "application" msgstr "" @@ -123,58 +124,74 @@ msgstr "" msgid "contact forms" msgstr "" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:86 msgid "file" msgstr "" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:237 +msgid "caption" +msgstr "" + +#: content/image/models.py:53 msgid "images" msgstr "" -#: content/image/models.py:42 content/medialibrary/models.py:105 +#: content/image/models.py:79 content/medialibrary/models.py:105 #: content/medialibrary/models.py:113 msgid "position" msgstr "" +#: content/image/models.py:87 +msgid "format" +msgstr "" + #: content/medialibrary/models.py:38 msgid "(no caption)" msgstr "" #: content/medialibrary/models.py:87 content/medialibrary/models.py:101 #: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/section/models.py:47 module/medialibrary/fields.py:45 +#: module/medialibrary/models.py:99 msgid "media file" msgstr "" #: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: module/medialibrary/models.py:100 msgid "media files" msgstr "" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:130 msgid "block" msgstr "" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:131 msgid "left" msgstr "" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:132 msgid "right" msgstr "" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:49 content/section/models.py:52 +#: content/section/models.py:60 content/table/models.py:81 msgid "type" msgstr "" @@ -187,7 +204,7 @@ msgid "raw contents" msgstr "" #: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 +#: content/section/models.py:32 msgid "text" msgstr "" @@ -244,11 +261,11 @@ msgstr "" msgid "RSS feeds" msgstr "" -#: content/section/models.py:37 +#: content/section/models.py:36 msgid "section" msgstr "" -#: content/section/models.py:38 +#: content/section/models.py:37 msgid "sections" msgstr "" @@ -276,53 +293,57 @@ msgstr "" msgid "data" msgstr "" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" msgstr "" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "" -#: module/blog/models.py:31 +#: contrib/tagging.py:113 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:29 msgid "published" msgstr "" -#: module/blog/models.py:33 module/page/models.py:259 +#: module/blog/models.py:31 msgid "This is used for the generated navigation too." msgstr "" -#: module/blog/models.py:36 +#: module/blog/models.py:34 msgid "published on" msgstr "" -#: module/blog/models.py:37 +#: module/blog/models.py:35 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" -#: module/blog/models.py:42 +#: module/blog/models.py:40 msgid "entry" msgstr "" -#: module/blog/models.py:43 +#: module/blog/models.py:41 msgid "entries" msgstr "" @@ -331,32 +352,52 @@ msgid "tags" msgstr "" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:105 msgid "translation of" msgstr "" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:108 msgid "Leave this empty for entries in the primary language." msgstr "" #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:36 msgid "creation date" msgstr "" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:37 msgid "modification date" msgstr "" -#: module/extensions/ct_tracker.py:133 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "" +#: module/extensions/datepublisher.py:48 +msgid "publication date" +msgstr "" + +#: module/extensions/datepublisher.py:50 +msgid "publication end date" +msgstr "" + +#: module/extensions/datepublisher.py:52 +msgid "Leave empty if the entry should stay active forever." +msgstr "" + +#: module/extensions/datepublisher.py:79 +msgid "visible from - to" +msgstr "" + +#: module/extensions/datepublisher.py:89 +msgid "Date-based publishing" +msgstr "" + #: module/extensions/featured.py:9 msgid "featured" msgstr "" @@ -385,229 +426,249 @@ msgstr "" msgid "Search engine optimization" msgstr "" -#: module/medialibrary/models.py:51 -msgid "parent" -msgstr "" - -#: module/medialibrary/models.py:53 module/page/models.py:260 -msgid "slug" -msgstr "" - -#: module/medialibrary/models.py:57 -msgid "category" +#: module/extensions/translations.py:175 +msgid "Edit translation" msgstr "" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 -msgid "categories" +#: module/extensions/translations.py:178 +msgid "Create translation" msgstr "" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" +#: module/extensions/translations.py:183 +msgid "translations" msgstr "" -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" +#: module/medialibrary/forms.py:25 +msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/models.py:93 -msgid "copyright" +#: module/medialibrary/forms.py:57 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "" +#: module/medialibrary/modeladmins.py:58 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" -#: module/medialibrary/models.py:203 -msgid "file info" +#: module/medialibrary/modeladmins.py:76 +msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/models.py:280 -msgid "Image" +#: module/medialibrary/modeladmins.py:85 +#, python-format +msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/models.py:281 -msgid "Video" +#: module/medialibrary/modeladmins.py:87 +#, python-format +msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/models.py:282 -msgid "Audio" +#: module/medialibrary/modeladmins.py:92 +msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/models.py:283 -msgid "PDF document" +#: module/medialibrary/modeladmins.py:141 +#: templates/admin/feincms/page/page/item_editor.html:14 +msgid "Preview" msgstr "" -#: module/medialibrary/models.py:284 -msgid "Flash" +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:90 +msgid "file size" msgstr "" -#: module/medialibrary/models.py:285 -msgid "Text" +#: module/medialibrary/modeladmins.py:151 module/medialibrary/models.py:88 +msgid "created" msgstr "" -#: module/medialibrary/models.py:286 -msgid "Rich Text" +#: module/medialibrary/modeladmins.py:170 module/medialibrary/models.py:87 +msgid "file type" msgstr "" -#: module/medialibrary/models.py:287 -msgid "Zip archive" +#: module/medialibrary/modeladmins.py:191 +msgid "file info" msgstr "" -#: module/medialibrary/models.py:288 -msgid "Microsoft Word" +#: module/medialibrary/modeladmins.py:203 +#, python-format +msgid "%d files imported" msgstr "" -#: module/medialibrary/models.py:289 -msgid "Microsoft Excel" +#: module/medialibrary/modeladmins.py:205 +#, python-format +msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/models.py:290 -msgid "Microsoft PowerPoint" +#: module/medialibrary/modeladmins.py:207 +msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:291 -msgid "Binary" +#: module/medialibrary/models.py:46 +msgid "parent" msgstr "" -#: module/medialibrary/models.py:307 -msgid "caption" +#: module/medialibrary/models.py:48 module/page/models.py:142 +msgid "slug" msgstr "" -#: module/medialibrary/models.py:308 -msgid "description" +#: module/medialibrary/models.py:52 +msgid "category" msgstr "" -#: module/medialibrary/models.py:311 -msgid "media file translation" +#: module/medialibrary/models.py:53 module/medialibrary/models.py:92 +msgid "categories" msgstr "" -#: module/medialibrary/models.py:312 -msgid "media file translations" +#: module/medialibrary/models.py:89 +msgid "copyright" msgstr "" -#: module/medialibrary/models.py:335 -#: templates/admin/feincms/page/page/item_editor.html:14 -msgid "Preview" +#: module/medialibrary/models.py:209 +msgid "Image" msgstr "" -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" - -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" +#: module/medialibrary/models.py:210 +msgid "Video" msgstr "" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" +#: module/medialibrary/models.py:211 +msgid "Audio" msgstr "" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/medialibrary/models.py:212 +msgid "PDF document" msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/medialibrary/models.py:213 +msgid "Flash" msgstr "" -#: module/page/models.py:255 -msgid "active" +#: module/medialibrary/models.py:214 +msgid "Text" msgstr "" -#: module/page/models.py:263 module/page/models.py:812 -msgid "in navigation" +#: module/medialibrary/models.py:215 +msgid "Rich Text" msgstr "" -#: module/page/models.py:264 -msgid "override URL" +#: module/medialibrary/models.py:216 +msgid "Zip archive" msgstr "" -#: module/page/models.py:265 -msgid "" -"Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." +#: module/medialibrary/models.py:217 +msgid "Microsoft Word" msgstr "" -#: module/page/models.py:266 -msgid "redirect to" +#: module/medialibrary/models.py:218 +msgid "Microsoft Excel" msgstr "" -#: module/page/models.py:267 -msgid "Target URL for automatic redirects." +#: module/medialibrary/models.py:219 +msgid "Microsoft PowerPoint" msgstr "" -#: module/page/models.py:268 -msgid "Cached URL" +#: module/medialibrary/models.py:220 +msgid "Binary" msgstr "" -#: module/page/models.py:279 -msgid "page" +#: module/medialibrary/models.py:238 +msgid "description" msgstr "" -#: module/page/models.py:280 -msgid "pages" +#: module/medialibrary/models.py:241 +msgid "media file translation" msgstr "" -#: module/page/models.py:297 module/page/models.py:884 -msgid "is active" +#: module/medialibrary/models.py:242 +msgid "media file translations" msgstr "" -#: module/page/models.py:735 +#: module/page/forms.py:113 msgid "This URL is already taken by an active page." msgstr "" -#: module/page/models.py:753 +#: module/page/forms.py:131 msgid "This URL is already taken by another active page." msgstr "" -#: module/page/models.py:775 +#: module/page/modeladmins.py:40 msgid "Other options" msgstr "" -#: module/page/models.py:823 +#: module/page/modeladmins.py:88 module/page/models.py:145 +msgid "in navigation" +msgstr "" + +#: module/page/modeladmins.py:99 msgid "Add child page" msgstr "" -#: module/page/models.py:825 templates/admin/feincms/content_inline.html:9 +#: module/page/modeladmins.py:101 +#: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "" -#: module/page/models.py:861 +#: module/page/modeladmins.py:129 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." +msgstr "" + +#: module/page/modeladmins.py:143 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/models.py:876 +#: module/page/modeladmins.py:158 msgid "inherited" msgstr "" -#: module/page/models.py:880 +#: module/page/modeladmins.py:162 msgid "extensions" msgstr "" -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" +#: module/page/modeladmins.py:166 module/page/models.py:179 +msgid "is active" msgstr "" -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" +#: module/page/models.py:138 +msgid "active" msgstr "" -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." +#: module/page/models.py:146 +msgid "override URL" msgstr "" -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" +#: module/page/models.py:147 +msgid "" +"Override the target URL. Be sure to include slashes at the beginning and at " +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." msgstr "" -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" +#: module/page/models.py:148 +msgid "redirect to" +msgstr "" + +#: module/page/models.py:149 +msgid "Target URL for automatic redirects." +msgstr "" + +#: module/page/models.py:150 +msgid "Cached URL" +msgstr "" + +#: module/page/models.py:161 +msgid "page" +msgstr "" + +#: module/page/models.py:162 +msgid "pages" msgstr "" #: module/page/extensions/excerpt.py:9 @@ -622,18 +683,18 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:74 +#: module/page/extensions/navigation.py:94 msgid "navigation extension" msgstr "" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:96 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "" -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:109 msgid "Navigation extension" msgstr "" @@ -681,18 +742,6 @@ msgstr "" msgid "Titles" msgstr "" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -780,7 +829,7 @@ msgstr "" msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "" @@ -837,19 +886,19 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "" @@ -886,7 +935,11 @@ msgstr "" msgid "Bulk upload a ZIP file:" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:21 +#: templates/admin/medialibrary/mediafile/change_list.html:22 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:25 msgid "Send" msgstr "" From c41640171d955ceef30389dfd27fa6973d412787 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 9 Mar 2012 17:04:43 +0100 Subject: [PATCH 0250/1590] Validate Category.parent some more --- feincms/module/medialibrary/forms.py | 8 ++++++++ feincms/module/medialibrary/modeladmins.py | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 2da9dd8ab..091673160 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -49,3 +49,11 @@ def clean_file(self): return self.cleaned_data['file'] # ------------------------------------------------------------------------ +class CategoryAdminForm(forms.ModelForm): + def clean_parent(self): + parent = self.cleaned_data.get('parent') + if parent and self.instance == parent: + raise forms.ValidationError(_('A category cannot be its own parent.')) + return parent + +# ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 95d055fca..c660dd41f 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -26,10 +26,11 @@ from ...translations import admin_translationinline, lookup_translations from .models import Category, MediaFileTranslation -from .forms import MediaFileAdminForm +from .forms import CategoryAdminForm, MediaFileAdminForm # ----------------------------------------------------------------------- class CategoryAdmin(admin.ModelAdmin): + form = CategoryAdminForm list_display = ['path'] list_filter = ['parent'] list_per_page = 25 From f0699dc457a14da82b5ff181305201e1bd3ba963 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 9 Mar 2012 18:17:46 +0100 Subject: [PATCH 0251/1590] Improve previous fix, don't offer a loop candidate in the first place. --- feincms/module/medialibrary/forms.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index b39c5f35e..fc5ba8ca8 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -26,6 +26,10 @@ def clean_parent(self): return data + def __init__(self,* args, **kwargs): + super(MediaCategoryAdminForm, self).__init__(*args, **kwargs) + self.fields['parent'].queryset = Category.objects.exclude(pk=self.instance.pk) + # ------------------------------------------------------------------------ class MediaFileAdminForm(forms.ModelForm): class Meta: From db27d2707420cb6d1e793c0464a209108841ed69 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 9 Mar 2012 18:23:52 +0100 Subject: [PATCH 0252/1590] Actually use the correct queryset for the drop down. --- feincms/module/medialibrary/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index fc5ba8ca8..001885625 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -28,7 +28,7 @@ def clean_parent(self): def __init__(self,* args, **kwargs): super(MediaCategoryAdminForm, self).__init__(*args, **kwargs) - self.fields['parent'].queryset = Category.objects.exclude(pk=self.instance.pk) + self.fields['parent'].queryset = self.fields['parent'].queryset.exclude(pk=self.instance.pk) # ------------------------------------------------------------------------ class MediaFileAdminForm(forms.ModelForm): From 09dc243a5cf1457abcb7b0d417306d41c7ecd0ea Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 10 Mar 2012 09:49:32 +0100 Subject: [PATCH 0253/1590] Fix #259: Installation location of data files (package data) in setuplib Change setuplib.find_files to return package_data instead of data_files. Big thanks to PSyton for the report and the suggestion how this issue should be fixed. --- setup.py | 4 ++-- setuplib.py | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index 295a48b6a..4cfc5d142 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import os import setuplib -packages, data_files = setuplib.find_files('feincms') +packages, package_data = setuplib.find_files('feincms') setup(name='FeinCMS', version=__import__('feincms').__version__, @@ -16,7 +16,7 @@ license='BSD License', platforms=['OS Independent'], packages=packages, - data_files=data_files, + package_data=package_data, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', diff --git a/setuplib.py b/setuplib.py index a95f8586f..1b16bca4c 100644 --- a/setuplib.py +++ b/setuplib.py @@ -21,30 +21,37 @@ def fullsplit(path, result=None): def find_files(package_dir): """ - Returns a tuple consisting of a list of packages and a list of data - files suitable for passing on to ``distutils.core.setup`` + Returns a tuple consisting of a ``packages`` list and a ``package_data`` + dictionary suitable for passing on to ``distutils.core.setup`` Requires the folder name containing the package files; ``find_files`` assumes that ``setup.py`` is located in the same folder as the folder containing those files. - Code lifted from Django's ``setup.py``, thanks! + Code lifted from Django's ``setup.py``, with improvements by PSyton. """ # Compile the list of packages available, because distutils doesn't have # an easy way to do this. - packages, data_files = [], [] + packages = [] + package_data = {} root_dir = os.path.dirname(__file__) if root_dir != '': os.chdir(root_dir) - for dirpath, dirnames, filenames in os.walk(package_dir): + for dirpath, dirnames, filenames in sorted(os.walk(package_dir)): # Ignore dirnames that start with '.' for i, dirname in enumerate(dirnames): if dirname.startswith('.'): del dirnames[i] if '__init__.py' in filenames: packages.append('.'.join(fullsplit(dirpath))) elif filenames: - data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) + cur_pack = packages[0] # Assign all data files to the toplevel package + if cur_pack not in package_data: + package_data[cur_pack] = [] + package_dir = "/".join(cur_pack.split(".")) + "/" + for f in filenames: + package_data[cur_pack].append(os.path.join(dirpath.replace(package_dir, ""), f)) + + return packages, package_data - return packages, data_files From 0420f5422c76b22b9032728371c1ef98a76dbc71 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 10 Mar 2012 09:51:37 +0100 Subject: [PATCH 0254/1590] Setuplib: find_packages is a better name for this method --- setup.py | 2 +- setuplib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 4cfc5d142..8038ffeb5 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import os import setuplib -packages, package_data = setuplib.find_files('feincms') +packages, package_data = setuplib.find_packages('feincms') setup(name='FeinCMS', version=__import__('feincms').__version__, diff --git a/setuplib.py b/setuplib.py index 1b16bca4c..a133afb0b 100644 --- a/setuplib.py +++ b/setuplib.py @@ -19,7 +19,7 @@ def fullsplit(path, result=None): return fullsplit(head, [tail] + result) -def find_files(package_dir): +def find_packages(package_dir): """ Returns a tuple consisting of a ``packages`` list and a ``package_data`` dictionary suitable for passing on to ``distutils.core.setup`` From 10c6ffb56866f46a0a464e249aa289d7dfa7bb2b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 10 Mar 2012 09:53:27 +0100 Subject: [PATCH 0255/1590] Include setuplib.py in MANIFEST.in Thanks to PSyton for the report. --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index 2b605a533..b5526e3b7 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,6 +2,7 @@ include AUTHORS include LICENSE include MANIFEST.in include README.rst +include setuplib.py recursive-include feincms/static * recursive-include feincms/locale * recursive-include feincms/templates * From afebe4942540ef54d24d1b973e86d94329b2a430 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 12 Mar 2012 12:08:56 +0100 Subject: [PATCH 0256/1590] feincms_navigation needs to deal with parents being inactive, issue #260. This is a stopgap measure for the most common case, but doesn't cover the case if active_filters has been extended. --- feincms/module/page/templatetags/feincms_page_tags.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index a029879d1..bf3ee4a9e 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -75,6 +75,7 @@ def _in_navigation_depth(self, level, depth): q = Q(level__lt=level + depth) for i in range(depth): q &= Q(level__lt=level + i) | Q(**{ + 'parent__' * i + 'active': True, 'parent__' * i + 'in_navigation': True, 'level__gte': level + i, }) From 65f5333823d224a8d727349af8010594aaef43aa Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 12 Mar 2012 13:11:34 +0100 Subject: [PATCH 0257/1590] Use RequestContext for MediaFileContent so we get all the TEMPLATE_CONTEXT_PROCESSORS goodness. --- feincms/content/medialibrary/models.py | 11 ++++++++--- feincms/content/medialibrary/v2.py | 9 +++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 6913a36e6..341324aa2 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -1,3 +1,7 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + """ Media library-based file inclusion tool. Can handle any type of media file, not only images. @@ -10,6 +14,7 @@ from django.contrib.admin.widgets import AdminRadioSelect from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.db import models +from django.template import RequestContext from django.template.loader import render_to_string from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ @@ -115,14 +120,14 @@ class MediaFileContentAdminForm(ItemEditorForm): cls.feincms_item_editor_form = MediaFileContentAdminForm - def render(self, **kwargs): - request = kwargs.get('request') + def render(self, request, **kwargs): return render_to_string([ 'content/mediafile/%s_%s.html' % (self.mediafile.type, self.position), 'content/mediafile/%s.html' % self.mediafile.type, 'content/mediafile/%s.html' % self.position, 'content/mediafile/default.html', - ], { 'content': self, 'request': request }) + ], { 'content': self }, context_instance=RequestContext(request)) + @classmethod def default_create_content_type(cls, cms_model): diff --git a/feincms/content/medialibrary/v2.py b/feincms/content/medialibrary/v2.py index 3d1ce4b6a..dccea6e24 100644 --- a/feincms/content/medialibrary/v2.py +++ b/feincms/content/medialibrary/v2.py @@ -1,5 +1,10 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + from django.contrib import admin from django.db import models +from django.template import RequestContext from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ @@ -49,7 +54,7 @@ def initialize_type(cls, TYPE_CHOICES=None): cls.add_to_class('type', models.CharField(_('type'), max_length=20, choices=TYPE_CHOICES, default=TYPE_CHOICES[0][0])) - def render(self, **kwargs): + def render(self, request, **kwargs): ctx = {'content': self} ctx.update(kwargs) @@ -58,4 +63,4 @@ def render(self, **kwargs): 'content/mediafile/%s.html' % self.mediafile.type, 'content/mediafile/%s.html' % self.type, 'content/mediafile/default.html', - ], ctx) + ], ctx, context_instance=RequestContext(request)) From d20792033335f002271d17e864c812b9a342668a Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 12 Mar 2012 13:39:44 +0100 Subject: [PATCH 0258/1590] Improve previous by using the context passed in from the content renderer. --- feincms/content/medialibrary/models.py | 6 ++---- feincms/content/medialibrary/v2.py | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 341324aa2..cb0cc8967 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -14,7 +14,6 @@ from django.contrib.admin.widgets import AdminRadioSelect from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.db import models -from django.template import RequestContext from django.template.loader import render_to_string from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ @@ -120,14 +119,13 @@ class MediaFileContentAdminForm(ItemEditorForm): cls.feincms_item_editor_form = MediaFileContentAdminForm - def render(self, request, **kwargs): + def render(self, **kwargs): return render_to_string([ 'content/mediafile/%s_%s.html' % (self.mediafile.type, self.position), 'content/mediafile/%s.html' % self.mediafile.type, 'content/mediafile/%s.html' % self.position, 'content/mediafile/default.html', - ], { 'content': self }, context_instance=RequestContext(request)) - + ], { 'content': self }, context_instance=kwargs.get('context')) @classmethod def default_create_content_type(cls, cms_model): diff --git a/feincms/content/medialibrary/v2.py b/feincms/content/medialibrary/v2.py index dccea6e24..577cf7d04 100644 --- a/feincms/content/medialibrary/v2.py +++ b/feincms/content/medialibrary/v2.py @@ -4,7 +4,6 @@ from django.contrib import admin from django.db import models -from django.template import RequestContext from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ @@ -54,13 +53,12 @@ def initialize_type(cls, TYPE_CHOICES=None): cls.add_to_class('type', models.CharField(_('type'), max_length=20, choices=TYPE_CHOICES, default=TYPE_CHOICES[0][0])) - def render(self, request, **kwargs): + def render(self, **kwargs): ctx = {'content': self} ctx.update(kwargs) - return render_to_string([ 'content/mediafile/%s_%s.html' % (self.mediafile.type, self.type), 'content/mediafile/%s.html' % self.mediafile.type, 'content/mediafile/%s.html' % self.type, 'content/mediafile/default.html', - ], ctx, context_instance=RequestContext(request)) + ], ctx, context_instance=kwargs.get('context')) From 259ed2613349a8cd161ff9dc269db54213e02643 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 12 Mar 2012 13:45:32 +0100 Subject: [PATCH 0259/1590] Also pass in context in other content types. --- feincms/content/file/models.py | 2 +- feincms/content/image/models.py | 2 +- feincms/content/richtext/models.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index cf5e2281c..5b8361378 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -29,5 +29,5 @@ def render(self, **kwargs): return render_to_string([ 'content/file/%s.html' % self.region, 'content/file/default.html', - ], {'content': self}) + ], {'content': self}, context_instance=kwargs.get('context')) diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index bedcedd6f..cbb0f3466 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -56,7 +56,7 @@ def render(self, **kwargs): return render_to_string([ 'content/image/%s.html' % self.position, 'content/image/default.html', - ], {'content': self}) + ], {'content': self}, context_instance=kwargs.get('context')) def get_image(self): type, separator, size = getattr(self, 'format', '').partition(':') diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index fe4fc84ee..e24a1161d 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -90,9 +90,8 @@ class Meta: verbose_name_plural = _('rich texts') def render(self, **kwargs): - request = kwargs.get('request') return render_to_string('content/richtext/default.html', - { 'content': self, 'request': request }) + { 'content': self }, context_instance=kwargs.get('context')) def save(self, *args, **kwargs): # TODO: Move this to the form? From 036acf45230a8c744c555010a81954122b0b7b0e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 12 Mar 2012 16:56:50 +0100 Subject: [PATCH 0260/1590] Add a blurb about the context availability to the release notes --- docs/releases/1.6.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/releases/1.6.rst b/docs/releases/1.6.rst index 2b8bb70ac..6c5d8ab38 100644 --- a/docs/releases/1.6.rst +++ b/docs/releases/1.6.rst @@ -71,3 +71,9 @@ FeinCMS 1.6 release notes (upcoming) done in an image filter (like sorl). Also, reading through the image data seems to have a side effect on some external storage engines which then would only save half the image data, see issue #254. + +* The bundled content types take additional steps to ensure that the main view + context is available in content types' templates. If you only use the rendering + tags (``feincms_render_region`` and ``feincms_render_content``) you can take + advantage of all variables from your context processors in content types' + templates too. From 0892696a3b9319d5b4c0ddf806a5d42665ede34d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 12 Mar 2012 20:54:33 +0100 Subject: [PATCH 0261/1590] FeinCMS v1.5.2 Be compatible with Django 1.4c1 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index f04a0a9e6..c0e474d5b 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 5, 1) +VERSION = (1, 5, 2) __version__ = '.'.join(map(str, VERSION)) From 23f7a81e6181b2b93cef23c4f257dbb67a5dbd17 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 13 Mar 2012 12:35:29 +0100 Subject: [PATCH 0262/1590] Start cleaning up test suite. --- tests/tests.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 79ffabe07..35ac934bc 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -2,6 +2,8 @@ from datetime import datetime, timedelta import os +import re + from django import forms, template from django.conf import settings @@ -18,7 +20,7 @@ from django.test import TestCase from feincms import settings as feincms_settings -from feincms.content.application.models import ApplicationContent, _empty_reverse_cache, reverse +from feincms.content.application.models import _empty_reverse_cache, app_reverse from feincms.content.contactform.models import ContactFormContent, ContactForm from feincms.content.file.models import FileContent from feincms.content.image.models import ImageContent @@ -226,9 +228,9 @@ class Meta: 'ct_tracker') Page.create_content_type(ContactFormContent, form=ContactForm) Page.create_content_type(FileContent) -Page.register_request_processors(processors.etag_request_processor) -Page.register_response_processors(processors.etag_response_processor) -Page.register_response_processors(processors.debug_sql_queries_response_processor()) +Page.register_request_processor(processors.etag_request_processor) +Page.register_response_processor(processors.etag_response_processor) +Page.register_response_processor(processors.debug_sql_queries_response_processor()) class PagesTestCase(TestCase): @@ -597,7 +599,7 @@ def test_10_mediafile_and_imagecontent(self): self.assertEqual(mf.translation.short_language_code(), short_language_code()) self.assertNotEqual(mf.get_absolute_url(), '') self.assertEqual(unicode(mf), 'something') - self.assertTrue(unicode(mf.file_type()).startswith(u'Image')) + self.assertTrue(mf.type == 'image') self.assertEqual(MediaFile.objects.only_language('de').count(), 0) self.assertEqual(MediaFile.objects.only_language('en').count(), 0) @@ -619,7 +621,7 @@ def test_10_mediafile_and_imagecontent(self): page._ct_inventory = None self.assertTrue('somefile.jpg' in page.content.main[2].render()) - self.assertTrue('thetitle' in page.content.main[3].render()) + self.assertTrue(re.search('.*thetitle.*', page.content.main[3].render(), re.MULTILINE + re.DOTALL) is not None) page.mediafilecontent_set.update(mediafile=3) # this should not raise @@ -1331,7 +1333,7 @@ def test_29_medialibrary_admin(self): 'data': open('test.zip'), }), '/admin/medialibrary/mediafile/') - self.assertEqual(MediaFile.objects.count(), 11) + self.assertEqual(MediaFile.objects.count(), 11, "Upload of media files with ZIP does not work") self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/add/', { 'file': open(os.path.join(os.path.dirname(os.path.dirname(__file__)), From dbc194d7af126781f60d3b8a60df3b8a69adc70f Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 13 Mar 2012 13:00:01 +0100 Subject: [PATCH 0263/1590] Add test to check if deactivating intermediate page also removes children from navigation. --- tests/tests.py | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 35ac934bc..e928ddadd 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -893,31 +893,52 @@ def test_17_feincms_navigation(self): self.login() - self.create_page('Page 1') + self.create_page('Page 1') # 1 self.create_page('Page 1.1', 1) - self.create_page('Page 1.2', 1) + self.create_page('Page 1.2', 1) # 3 self.create_page('Page 1.2.1', 3) self.create_page('Page 1.2.2', 3) self.create_page('Page 1.2.3', 3) self.create_page('Page 1.3', 1) - self.create_page('Page 2') + self.create_page('Page 2') # 8 self.create_page('Page 2.1', 8) self.create_page('Page 2.2', 8) self.create_page('Page 2.3', 8) - self.create_page('Page 3') + self.create_page('Page 3') # 12 self.create_page('Page 3.1', 12) self.create_page('Page 3.2', 12) - self.create_page('Page 3.3', 12) - self.create_page('Page 3.3.1', 15) + self.create_page('Page 3.3', 12) # 15 + self.create_page('Page 3.3.1', 15) # 16 self.create_page('Page 3.3.1.1', 16) self.create_page('Page 3.3.2', 15) - self.create_page('Page 4') + self.create_page('Page 4') # 19 self.create_page('Page 4.1', 19) self.create_page('Page 4.2', 19) + """ + Creates the following structure: + + 1 (1) -+- 1.1 (2) + +- 1.2 (3) -+- 1.2.1 (4) + | +- 1.2.2 (5) + | +- 1.2.3 (6) + +- 1.3 (7) + + 2 (8) -+- 2.1 (9) + +- 2.2 (10) + +- 2.3 (11) + + 3 (12) -+- 3.1 (13) + +- 3.2 (14) + +- 3.3 (15) -+- 3.3.1 (16) --- 3.3.1.1 (17) + +- 3.3.2 (18) + 4 (19) -+- 4.1 (20) + +- 4.2 (21) + """ + Page.objects.all().update(active=True, in_navigation=True) Page.objects.filter(id__in=(5, 9, 19)).update(in_navigation=False) @@ -962,6 +983,20 @@ def test_17_feincms_navigation(self): template.Template(t).render(template.Context(c)), r) + # Now check that disabling a page also disables it in Navigation: + p = Page.objects.get(pk=15) + tmpl = '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=3 %}{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %}' + + data = template.Template(tmpl).render(template.Context({'feincms_page': p})), + self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") + + p.active = False + p.save() + data = template.Template(tmpl).render(template.Context({'feincms_page': p})), + self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") + +# print "**********", data + def test_18_default_render_method(self): """ Test the default render() behavior of selecting render_ methods From c221b8b410a843043a7f272ef06747cd5667aaef Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 13 Mar 2012 13:13:49 +0100 Subject: [PATCH 0264/1590] Start separating the rather unwieldy tests.py into smaller parts. --- tests/tests/__init__.py | 7 ++ tests/tests/cms_tests.py | 145 +++++++++++++++++++++++++++++++++++++ tests/{ => tests}/tests.py | 140 +---------------------------------- 3 files changed, 156 insertions(+), 136 deletions(-) create mode 100644 tests/tests/__init__.py create mode 100644 tests/tests/cms_tests.py rename tests/{ => tests}/tests.py (91%) diff --git a/tests/tests/__init__.py b/tests/tests/__init__.py new file mode 100644 index 000000000..eaef8c57c --- /dev/null +++ b/tests/tests/__init__.py @@ -0,0 +1,7 @@ + +from __future__ import absolute_import + + +from .cms_tests import * +from .tests import * + diff --git a/tests/tests/cms_tests.py b/tests/tests/cms_tests.py new file mode 100644 index 000000000..39b5514ca --- /dev/null +++ b/tests/tests/cms_tests.py @@ -0,0 +1,145 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.test import TestCase + +from feincms.content.contactform.models import ContactFormContent +from feincms.content.file.models import FileContent +from feincms.content.image.models import ImageContent +from feincms.content.raw.models import RawContent +from feincms.content.richtext.models import RichTextContent +from feincms.content.video.models import VideoContent + +from .tests import ExampleCMSBase, Empty, ExampleCMSBase2 + +# ------------------------------------------------------------------------ +class CMSBaseTest(TestCase): + def test_01_simple_content_type_creation(self): + self.assertEqual(ExampleCMSBase.content_type_for(FileContent), None) + + ExampleCMSBase.create_content_type(ContactFormContent) + ExampleCMSBase.create_content_type(FileContent, regions=('region2',)) + + # no POSITION_CHOICES, should raise + self.assertRaises(ImproperlyConfigured, + lambda: ExampleCMSBase.create_content_type(ImageContent)) + + ExampleCMSBase.create_content_type(RawContent) + ExampleCMSBase.create_content_type(RichTextContent) + + # test creating a cotent with arguments, but no initialize_type classmethod + ExampleCMSBase.create_content_type(VideoContent, arbitrary_arg='arbitrary_value') + + # content_type_for should return None if it does not have a subclass registered + self.assertEqual(ExampleCMSBase.content_type_for(Empty), None) + + self.assertTrue('filecontent' not in dict(ExampleCMSBase.template.regions[0].content_types).keys()) + self.assertTrue('filecontent' in dict(ExampleCMSBase.template.regions[1].content_types).keys()) + + def test_02_rsscontent_creation(self): + # this test resides in its own method because the required feedparser + # module is not available everywhere + from feincms.content.rss.models import RSSContent + type = ExampleCMSBase.create_content_type(RSSContent) + obj = type() + + self.assertTrue('yahoo' not in obj.render()) + + obj.link = 'http://rss.news.yahoo.com/rss/topstories' + obj.cache_content(save=False) + + self.assertTrue('yahoo' in obj.render()) + + #Creating a content type twice isn't forbidden anymore + #def test_03_double_creation(self): + # # creating a content type twice is forbidden + # self.assertRaises(ImproperlyConfigured, + # lambda: ExampleCMSBase.create_content_type(RawContent)) + + def test_04_mediafilecontent_creation(self): + # the medialibrary needs to be enabled, otherwise this test fails + + from feincms.content.medialibrary.models import MediaFileContent + + # no POSITION_CHOICES, should raise + self.assertRaises(ImproperlyConfigured, + lambda: ExampleCMSBase.create_content_type(MediaFileContent)) + + def test_05_non_abstract_content_type(self): + # Should not be able to create a content type from a non-abstract base type + class TestContentType(models.Model): + pass + + self.assertRaises(ImproperlyConfigured, + lambda: ExampleCMSBase.create_content_type(TestContentType)) + + def test_06_videocontent(self): + type = ExampleCMSBase.content_type_for(VideoContent) + obj = type() + obj.video = 'http://www.youtube.com/watch?v=zmj1rpzDRZ0' + + self.assertTrue('x-shockwave-flash' in obj.render()) + + self.assertEqual(getattr(type, 'arbitrary_arg'), 'arbitrary_value') + + obj.video = 'http://www.example.com/' + + self.assertTrue(obj.video in obj.render()) + + def test_07_default_render_method(self): + class SomethingElse(models.Model): + class Meta: + abstract = True + + def render_region(self): + return 'hello' + + type = ExampleCMSBase.create_content_type(SomethingElse) + obj = type() + self.assertRaises(NotImplementedError, lambda: obj.render()) + + obj.region = 'region' + self.assertEqual(obj.render(), 'hello') + + def test_08_creating_two_content_types_in_same_application(self): + ExampleCMSBase.create_content_type(RawContent) + ct = ExampleCMSBase.content_type_for(RawContent) + self.assertEqual(ct._meta.db_table, 'tests_examplecmsbase_rawcontent') + + ExampleCMSBase2.create_content_type(RawContent, class_name='RawContent2') + ct2 = ExampleCMSBase2.content_type_for(RawContent) + self.assertEqual(ct2._meta.db_table, 'tests_examplecmsbase2_rawcontent2') + + def test_09_related_objects_cache(self): + """ + We need to define a model with relationship to our Base *after* all + content types have been registered; previously _fill_*_cache methods + were called during each content type registration, so any new related + objects added after the last content type time missed the boat. Now we + delete the cache so hopefully _fill_*_cache* won't be called until all + related models have been defined. + """ + class Attachment(models.Model): + base = models.ForeignKey(ExampleCMSBase, related_name='test_related_name') + + related_models = map( + lambda x: x.model, ExampleCMSBase._meta.get_all_related_objects()) + + self.assertTrue(Attachment in related_models) + self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) + #self.assertFalse(hasattr(Attachment, 'anycontents')) + + class AnyContent(models.Model): + attachment = models.ForeignKey(Attachment, related_name='anycontents') + class Meta: + abstract = True + ct = ExampleCMSBase.create_content_type(AnyContent) + + self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) + self.assertTrue(hasattr(Attachment, 'anycontents')) + diff --git a/tests/tests.py b/tests/tests/tests.py similarity index 91% rename from tests/tests.py rename to tests/tests/tests.py index e928ddadd..9363c0e61 100644 --- a/tests/tests.py +++ b/tests/tests/tests.py @@ -1,16 +1,16 @@ +# ------------------------------------------------------------------------ # coding=utf-8 +# ------------------------------------------------------------------------ from datetime import datetime, timedelta import os import re - from django import forms, template from django.conf import settings from django.contrib.auth.models import User, AnonymousUser from django.contrib.contenttypes.models import ContentType from django.core import mail -from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import reverse from django.db import models from django.contrib.sites.models import Site @@ -20,13 +20,12 @@ from django.test import TestCase from feincms import settings as feincms_settings -from feincms.content.application.models import _empty_reverse_cache, app_reverse +from feincms.content.application.models import _empty_reverse_cache from feincms.content.contactform.models import ContactFormContent, ContactForm from feincms.content.file.models import FileContent from feincms.content.image.models import ImageContent from feincms.content.raw.models import RawContent from feincms.content.richtext.models import RichTextContent -from feincms.content.video.models import VideoContent from feincms.context_processors import add_page_if_missing from feincms.models import Region, Template, Base, ContentProxy @@ -38,7 +37,7 @@ from feincms.translations import short_language_code from feincms.utils import collect_dict_values, get_object - +# ------------------------------------------------------------------------ class Empty(object): """ Helper class to use as request substitute (or whatever) @@ -96,133 +95,6 @@ class ExampleCMSBase2(Base): ExampleCMSBase2.register_regions(('region', 'region title'), ('region2', 'region2 title')) - -class CMSBaseTest(TestCase): - def test_01_simple_content_type_creation(self): - self.assertEqual(ExampleCMSBase.content_type_for(FileContent), None) - - ExampleCMSBase.create_content_type(ContactFormContent) - ExampleCMSBase.create_content_type(FileContent, regions=('region2',)) - - # no POSITION_CHOICES, should raise - self.assertRaises(ImproperlyConfigured, - lambda: ExampleCMSBase.create_content_type(ImageContent)) - - ExampleCMSBase.create_content_type(RawContent) - ExampleCMSBase.create_content_type(RichTextContent) - - # test creating a cotent with arguments, but no initialize_type classmethod - ExampleCMSBase.create_content_type(VideoContent, arbitrary_arg='arbitrary_value') - - # content_type_for should return None if it does not have a subclass registered - self.assertEqual(ExampleCMSBase.content_type_for(Empty), None) - - self.assertTrue('filecontent' not in dict(ExampleCMSBase.template.regions[0].content_types).keys()) - self.assertTrue('filecontent' in dict(ExampleCMSBase.template.regions[1].content_types).keys()) - - def test_02_rsscontent_creation(self): - # this test resides in its own method because the required feedparser - # module is not available everywhere - from feincms.content.rss.models import RSSContent - type = ExampleCMSBase.create_content_type(RSSContent) - obj = type() - - self.assertTrue('yahoo' not in obj.render()) - - obj.link = 'http://rss.news.yahoo.com/rss/topstories' - obj.cache_content(save=False) - - self.assertTrue('yahoo' in obj.render()) - - #Creating a content type twice isn't forbidden anymore - #def test_03_double_creation(self): - # # creating a content type twice is forbidden - # self.assertRaises(ImproperlyConfigured, - # lambda: ExampleCMSBase.create_content_type(RawContent)) - - def test_04_mediafilecontent_creation(self): - # the medialibrary needs to be enabled, otherwise this test fails - - from feincms.content.medialibrary.models import MediaFileContent - - # no POSITION_CHOICES, should raise - self.assertRaises(ImproperlyConfigured, - lambda: ExampleCMSBase.create_content_type(MediaFileContent)) - - def test_05_non_abstract_content_type(self): - # Should not be able to create a content type from a non-abstract base type - class TestContentType(models.Model): - pass - - self.assertRaises(ImproperlyConfigured, - lambda: ExampleCMSBase.create_content_type(TestContentType)) - - def test_06_videocontent(self): - type = ExampleCMSBase.content_type_for(VideoContent) - obj = type() - obj.video = 'http://www.youtube.com/watch?v=zmj1rpzDRZ0' - - self.assertTrue('x-shockwave-flash' in obj.render()) - - self.assertEqual(getattr(type, 'arbitrary_arg'), 'arbitrary_value') - - obj.video = 'http://www.example.com/' - - self.assertTrue(obj.video in obj.render()) - - def test_07_default_render_method(self): - class SomethingElse(models.Model): - class Meta: - abstract = True - - def render_region(self): - return 'hello' - - type = ExampleCMSBase.create_content_type(SomethingElse) - obj = type() - self.assertRaises(NotImplementedError, lambda: obj.render()) - - obj.region = 'region' - self.assertEqual(obj.render(), 'hello') - - def test_08_creating_two_content_types_in_same_application(self): - ExampleCMSBase.create_content_type(RawContent) - ct = ExampleCMSBase.content_type_for(RawContent) - self.assertEqual(ct._meta.db_table, 'tests_examplecmsbase_rawcontent') - - ExampleCMSBase2.create_content_type(RawContent, class_name='RawContent2') - ct2 = ExampleCMSBase2.content_type_for(RawContent) - self.assertEqual(ct2._meta.db_table, 'tests_examplecmsbase2_rawcontent2') - - def test_09_related_objects_cache(self): - """ - We need to define a model with relationship to our Base *after* all - content types have been registered; previously _fill_*_cache methods - were called during each content type registration, so any new related - objects added after the last content type time missed the boat. Now we - delete the cache so hopefully _fill_*_cache* won't be called until all - related models have been defined. - """ - class Attachment(models.Model): - base = models.ForeignKey(ExampleCMSBase, related_name='test_related_name') - - related_models = map( - lambda x: x.model, ExampleCMSBase._meta.get_all_related_objects()) - - self.assertTrue(Attachment in related_models) - self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) - #self.assertFalse(hasattr(Attachment, 'anycontents')) - - class AnyContent(models.Model): - attachment = models.ForeignKey(Attachment, related_name='anycontents') - class Meta: - abstract = True - ct = ExampleCMSBase.create_content_type(AnyContent) - - self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) - self.assertTrue(hasattr(Attachment, 'anycontents')) - - Page.register_extensions('datepublisher', 'navigation', 'seo', 'symlinks', 'titles', 'translations', 'seo', 'changedate', 'ct_tracker') @@ -239,7 +111,6 @@ def setUp(self): u.set_password('test') u.save() - self.site_1 = Site.objects.all()[0] Page.register_templates({ @@ -995,8 +866,6 @@ def test_17_feincms_navigation(self): data = template.Template(tmpl).render(template.Context({'feincms_page': p})), self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") -# print "**********", data - def test_18_default_render_method(self): """ Test the default render() behavior of selecting render_ methods @@ -1477,7 +1346,6 @@ def test_34_access(self): r = self.client.get('/foo/') self.assertEquals(r.status_code, 404) - def test_35_access_with_extra_path(self): self.login() self.create_page(title='redirect again', override_url='/', redirect_to='/somewhere/', active=True) From 12683442f1492e55b96df66cf2f58a9b23a9c2de Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 13 Mar 2012 13:19:58 +0100 Subject: [PATCH 0265/1590] More splitting out tests. --- tests/tests/__init__.py | 6 +- tests/tests/page_tests.py | 1301 +++++++++++++++++++++++++++++++++++++ tests/tests/tests.py | 1261 ----------------------------------- 3 files changed, 1306 insertions(+), 1262 deletions(-) create mode 100644 tests/tests/page_tests.py diff --git a/tests/tests/__init__.py b/tests/tests/__init__.py index eaef8c57c..fba82e47e 100644 --- a/tests/tests/__init__.py +++ b/tests/tests/__init__.py @@ -1,7 +1,11 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ from __future__ import absolute_import - from .cms_tests import * +from .page_tests import * from .tests import * +# ------------------------------------------------------------------------ diff --git a/tests/tests/page_tests.py b/tests/tests/page_tests.py new file mode 100644 index 000000000..60045bbc6 --- /dev/null +++ b/tests/tests/page_tests.py @@ -0,0 +1,1301 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import absolute_import + +from datetime import datetime, timedelta +import os +import re + + +from django import forms, template +from django.conf import settings +from django.contrib.auth.models import User, AnonymousUser +from django.contrib.contenttypes.models import ContentType +from django.core import mail +from django.core.urlresolvers import reverse +from django.db import models +from django.contrib.sites.models import Site +from django.http import Http404, HttpResponseBadRequest +from django.template import TemplateDoesNotExist +from django.template.defaultfilters import slugify +from django.test import TestCase + +from feincms import settings as feincms_settings +from feincms.content.application.models import _empty_reverse_cache +from feincms.content.image.models import ImageContent +from feincms.content.raw.models import RawContent +from feincms.content.richtext.models import RichTextContent + +from feincms.context_processors import add_page_if_missing +from feincms.models import ContentProxy +from feincms.module.medialibrary.models import Category, MediaFile +from feincms.module.page.models import Page +from feincms.templatetags import feincms_tags +from feincms.translations import short_language_code + +from .tests import Empty + +# ------------------------------------------------------------------------ + +class PagesTestCase(TestCase): + def setUp(self): + u = User(username='test', is_active=True, is_staff=True, is_superuser=True) + u.set_password('test') + u.save() + + self.site_1 = Site.objects.all()[0] + + Page.register_templates({ + 'key': 'base', + 'title': 'Standard template', + 'path': 'feincms_base.html', + 'regions': ( + ('main', 'Main content area'), + ('sidebar', 'Sidebar', 'inherited'), + ), + }, { + 'key': 'theother', + 'title': 'This actually exists', + 'path': 'base.html', + 'regions': ( + ('main', 'Main content area'), + ('sidebar', 'Sidebar', 'inherited'), + ), + }) + + def login(self): + self.assertTrue(self.client.login(username='test', password='test')) + + def create_page(self, title='Test page', parent='', **kwargs): + dic = { + 'title': title, + 'slug': kwargs.get('slug', slugify(title)), + 'parent': parent, + 'template_key': 'base', + 'publication_date_0': '2009-01-01', + 'publication_date_1': '00:00:00', + 'initial-publication_date_0': '2009-01-01', + 'initial-publication_date_1': '00:00:00', + 'language': 'en', + 'site': self.site_1.id, + + 'rawcontent_set-TOTAL_FORMS': 0, + 'rawcontent_set-INITIAL_FORMS': 0, + 'rawcontent_set-MAX_NUM_FORMS': 10, + + 'mediafilecontent_set-TOTAL_FORMS': 0, + 'mediafilecontent_set-INITIAL_FORMS': 0, + 'mediafilecontent_set-MAX_NUM_FORMS': 10, + + 'imagecontent_set-TOTAL_FORMS': 0, + 'imagecontent_set-INITIAL_FORMS': 0, + 'imagecontent_set-MAX_NUM_FORMS': 10, + + 'contactformcontent_set-TOTAL_FORMS': 0, + 'contactformcontent_set-INITIAL_FORMS': 0, + 'contactformcontent_set-MAX_NUM_FORMS': 10, + + 'filecontent_set-TOTAL_FORMS': 0, + 'filecontent_set-INITIAL_FORMS': 0, + 'filecontent_set-MAX_NUM_FORMS': 10, + + 'applicationcontent_set-TOTAL_FORMS': 0, + 'applicationcontent_set-INITIAL_FORMS': 0, + 'applicationcontent_set-MAX_NUM_FORMS': 10, + } + dic.update(kwargs) + return self.client.post('/admin/page/page/add/', dic) + + def create_default_page_set(self): + self.login() + self.create_page() + return self.create_page('Test child page', 1) + + def is_published(self, url, should_be=True): + try: + self.client.get(url) + except TemplateDoesNotExist, e: + if should_be: + if e.args != ('feincms_base.html',): + raise + else: + if e.args != ('404.html',): + raise + + def test_01_tree_editor(self): + self.login() + self.assertEqual(self.client.get('/admin/page/page/').status_code, 200) + + self.assertRedirects(self.client.get('/admin/page/page/?anything=anything'), + '/admin/page/page/?e=1') + + def test_02_add_page(self): + self.login() + self.assertRedirects(self.create_page(title='Test page ' * 10, slug='test-page'), + '/admin/page/page/') + self.assertEqual(Page.objects.count(), 1) + self.assertContains(self.client.get('/admin/page/page/'), '…') + + def test_03_item_editor(self): + self.login() + self.assertRedirects(self.create_page(_continue=1), '/admin/page/page/1/') + self.assertEqual(self.client.get('/admin/page/page/1/').status_code, 200) + self.is_published('/admin/page/page/42/', should_be=False) + + def test_03_add_another(self): + self.login() + self.assertRedirects(self.create_page(_addanother=1), '/admin/page/page/add/') + + def test_04_add_child(self): + response = self.create_default_page_set() + self.assertRedirects(response, '/admin/page/page/') + self.assertEqual(Page.objects.count(), 2) + + page = Page.objects.get(pk=2) + self.assertEqual(page.get_absolute_url(), '/test-page/test-child-page/') + + page.active = True + page.in_navigation = True + page.save() + + # page2 inherited the inactive flag from the toplevel page + self.assertContains(self.client.get('/admin/page/page/'), 'inherited') + + page1 = Page.objects.get(pk=1) + page1.active = True + page1.save() + + self.assertEqual(len(self.client.get('/admin/page/page/').content.split('checked="checked"')), 4) + + def test_05_override_url(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + page.override_url = '/something/' + page.save() + + page2 = Page.objects.get(pk=2) + self.assertEqual(page2.get_absolute_url(), '/something/test-child-page/') + + page.override_url = '/' + page.save() + page2 = Page.objects.get(pk=2) + self.assertEqual(page2.get_absolute_url(), '/test-child-page/') + + # This goes through feincms.views.base.handler instead of the applicationcontent handler + self.is_published('/', False) + page.active = True + page.template_key = 'theother' + page.save() + self.is_published('/', True) + + def test_06_tree_editor_save(self): + self.create_default_page_set() + + page1 = Page.objects.get(pk=1) + page2 = Page.objects.get(pk=2) + + page3 = Page.objects.create(title='page3', slug='page3', parent=page2) + page4 = Page.objects.create(title='page4', slug='page4', parent=page1) + page5 = Page.objects.create(title='page5', slug='page5', parent=None) + + self.assertEqual(page3.get_absolute_url(), '/test-page/test-child-page/page3/') + self.assertEqual(page4.get_absolute_url(), '/test-page/page4/') + self.assertEqual(page5.get_absolute_url(), '/page5/') + + self.client.post('/admin/page/page/', { + '__cmd': 'move_node', + 'position': 'last-child', + 'cut_item': '1', + 'pasted_on': '5', + }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + + self.assertEqual(Page.objects.get(pk=1).get_absolute_url(), + '/page5/test-page/') + self.assertEqual(Page.objects.get(pk=5).get_absolute_url(), + '/page5/') + self.assertEqual(Page.objects.get(pk=3).get_absolute_url(), + '/page5/test-page/test-child-page/page3/') + + def test_07_tree_editor_toggle_boolean(self): + self.create_default_page_set() + + self.assertEqual(Page.objects.get(pk=1).in_navigation, False) + + self.assertContains(self.client.post('/admin/page/page/', { + '__cmd': 'toggle_boolean', + 'item_id': 1, + 'attr': 'in_navigation', + }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), + r'checked=\"checked\"') + self.assertEqual(Page.objects.get(pk=1).in_navigation, True) + self.assertNotContains(self.client.post('/admin/page/page/', { + '__cmd': 'toggle_boolean', + 'item_id': 1, + 'attr': 'in_navigation', + }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), + 'checked="checked"') + self.assertEqual(Page.objects.get(pk=1).in_navigation, False) + + self.assertTrue(isinstance(self.client.post('/admin/page/page/', { + '__cmd': 'toggle_boolean', + 'item_id': 1, + 'attr': 'notexists', + }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), HttpResponseBadRequest)) + + def test_07_tree_editor_invalid_ajax(self): + self.login() + self.assertContains(self.client.post('/admin/page/page/', { + '__cmd': 'notexists', + }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), + 'Oops. AJAX request not understood.', + status_code=400) + + def test_08_publishing(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + page2 = Page.objects.get(pk=2) + self.is_published(page.get_absolute_url(), should_be=False) + self.is_published(page2.get_absolute_url(), should_be=False) + + page.active = True + page.save() + page2.active = True + page2.save() + self.is_published(page.get_absolute_url(), should_be=True) + self.is_published(page2.get_absolute_url(), should_be=True) + + old_publication = page.publication_date + page.publication_date = datetime.now() + timedelta(days=1) + page.save() + self.is_published(page.get_absolute_url(), should_be=False) + + # Should be not accessible because of its parent's inactivity + self.is_published(page2.get_absolute_url(), should_be=False) + + page.publication_date = old_publication + page.publication_end_date = datetime.now() - timedelta(days=1) + page.save() + self.is_published(page.get_absolute_url(), should_be=False) + + # Should be not accessible because of its parent's inactivity + self.is_published(page2.get_absolute_url(), should_be=False) + + page.publication_end_date = datetime.now() + timedelta(days=1) + page.save() + self.is_published(page.get_absolute_url(), should_be=True) + self.is_published(page2.get_absolute_url(), should_be=True) + + def create_pagecontent(self, page, **kwargs): + data = { + 'title': page.title, + 'slug': page.slug, + #'parent': page.parent_id, # this field is excluded from the form + 'template_key': page.template_key, + 'publication_date_0': '2009-01-01', + 'publication_date_1': '00:00:00', + 'initial-publication_date_0': '2009-01-01', + 'initial-publication_date_1': '00:00:00', + 'language': 'en', + 'site': self.site_1.id, + + 'rawcontent_set-TOTAL_FORMS': 1, + 'rawcontent_set-INITIAL_FORMS': 0, + 'rawcontent_set-MAX_NUM_FORMS': 10, + + 'rawcontent_set-0-parent': 1, + 'rawcontent_set-0-region': 'main', + 'rawcontent_set-0-ordering': 0, + 'rawcontent_set-0-text': 'This is some example content', + + 'mediafilecontent_set-TOTAL_FORMS': 1, + 'mediafilecontent_set-INITIAL_FORMS': 0, + 'mediafilecontent_set-MAX_NUM_FORMS': 10, + + 'mediafilecontent_set-0-parent': 1, + 'mediafilecontent_set-0-position': 'block', + + 'imagecontent_set-TOTAL_FORMS': 1, + 'imagecontent_set-INITIAL_FORMS': 0, + 'imagecontent_set-MAX_NUM_FORMS': 10, + + 'imagecontent_set-0-parent': 1, + 'imagecontent_set-0-position': 'default', + + 'contactformcontent_set-TOTAL_FORMS': 1, + 'contactformcontent_set-INITIAL_FORMS': 0, + 'contactformcontent_set-MAX_NUM_FORMS': 10, + + 'filecontent_set-TOTAL_FORMS': 1, + 'filecontent_set-INITIAL_FORMS': 0, + 'filecontent_set-MAX_NUM_FORMS': 10, + + 'applicationcontent_set-TOTAL_FORMS': 1, + 'applicationcontent_set-INITIAL_FORMS': 0, + 'applicationcontent_set-MAX_NUM_FORMS': 10, + } + data.update(kwargs) + + return self.client.post('/admin/page/page/%s/' % page.pk, data) + + def test_09_pagecontent(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + response = self.create_pagecontent(page) + self.assertRedirects(response, '/admin/page/page/') + self.assertEqual(page.content.main[0].__class__.__name__, 'RawContent') + + page2 = Page.objects.get(pk=2) + page2.symlinked_page = page + + # Test that all_of_type works correctly even before accessing + # other content methods + self.assertEqual(len(page2.content.all_of_type(RawContent)), 1) + + self.assertEqual(page2.content.main[0].__class__.__name__, 'RawContent') + self.assertEqual(unicode(page2.content.main[0]), + 'main on Test page, ordering 0') + + self.assertEqual(len(page2.content.main), 1) + self.assertEqual(len(page2.content.sidebar), 0) + self.assertEqual(len(page2.content.nonexistant_region), 0) + + self.assertTrue(isinstance(page2.content.media, forms.Media)) + + self.assertEqual(len(page2.content.all_of_type(RawContent)), 1) + self.assertEqual(len(page2.content.all_of_type((ImageContent,))), 0) + self.assertEqual(len(page2.content.all_of_type([ImageContent])), 0) + + def test_10_mediafile_and_imagecontent(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + self.create_pagecontent(page) + + category = Category.objects.create(title='Category', parent=None) + category2 = Category.objects.create(title='Something', parent=category) + + self.assertEqual(unicode(category2), 'Category - Something') + self.assertEqual(unicode(category), 'Category') + + mediafile = MediaFile.objects.create(file='somefile.jpg') + mediafile.categories = [category] + page.mediafilecontent_set.create( + mediafile=mediafile, + region='main', + position='block', + ordering=1) + + self.assertEqual(unicode(mediafile), 'somefile.jpg') + + mediafile.translations.create(caption='something', + language_code='%s-ha' % short_language_code()) + mediafile.purge_translation_cache() + + self.assertTrue('something' in unicode(mediafile)) + + mf = page.content.main[1].mediafile + + self.assertEqual(mf.translation.caption, 'something') + self.assertEqual(mf.translation.short_language_code(), short_language_code()) + self.assertNotEqual(mf.get_absolute_url(), '') + self.assertEqual(unicode(mf), 'something') + self.assertTrue(mf.type == 'image') + + self.assertEqual(MediaFile.objects.only_language('de').count(), 0) + self.assertEqual(MediaFile.objects.only_language('en').count(), 0) + self.assertEqual(MediaFile.objects.only_language('%s-ha' % short_language_code()).count(), + 1) + + self.assertTrue('%s-ha' % short_language_code() in mf.available_translations) + + # this should not raise + self.client.get('/admin/page/page/1/') + + #self.assertTrue('alt="something"' in page.content.main[1].render()) Since it isn't an image + + page.imagecontent_set.create(image='somefile.jpg', region='main', position='default', ordering=2) + page.filecontent_set.create(file='somefile.jpg', title='thetitle', region='main', ordering=3) + + # Reload page, reset _ct_inventory + page = Page.objects.get(pk=page.pk) + page._ct_inventory = None + + self.assertTrue('somefile.jpg' in page.content.main[2].render()) + self.assertTrue(re.search('.*thetitle.*', page.content.main[3].render(), re.MULTILINE + re.DOTALL) is not None) + + page.mediafilecontent_set.update(mediafile=3) + # this should not raise + self.client.get('/admin/page/page/1/') + + field = MediaFile._meta.get_field('file') + old = (field.upload_to, field.storage, field.generate_filename) + from django.core.files.storage import FileSystemStorage + MediaFile.reconfigure(upload_to=lambda: 'anywhere', + storage=FileSystemStorage(location='/wha/', base_url='/whe/')) + mediafile = MediaFile.objects.get(pk=1) + self.assertEqual(mediafile.file.url, '/whe/somefile.jpg') + + # restore settings + (field.upload_to, field.storage, field.generate_filename) = old + + mediafile = MediaFile.objects.get(pk=1) + self.assertEqual(mediafile.file.url, 'somefile.jpg') + + def test_11_translations(self): + self.create_default_page_set() + + page1 = Page.objects.get(pk=1) + self.assertEqual(len(page1.available_translations()), 0) + + page1 = Page.objects.get(pk=1) + page2 = Page.objects.get(pk=2) + + page2.language = 'de' + page2.save() + + self.assertEqual(len(page2.available_translations()), 0) + + page2.translation_of = page1 + page2.save() + + self.assertEqual(len(page2.available_translations()), 1) + self.assertEqual(len(page1.available_translations()), 1) + + self.assertEqual(page1, page1.original_translation) + self.assertEqual(page1, page2.original_translation) + + def test_12_titles(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + + self.assertEqual(page.page_title, page.title) + self.assertEqual(page.content_title, page.title) + + page._content_title = 'Something\nawful' + page._page_title = 'Hello world' + page.save() + + self.assertEqual(page.page_title, 'Hello world') + self.assertEqual(page.content_title, 'Something') + self.assertEqual(page.content_subtitle, 'awful') + + page._content_title = 'Only one line' + self.assertEqual(page.content_title, 'Only one line') + self.assertEqual(page.content_subtitle, '') + + page._content_title = '' + self.assertEqual(page.content_title, page.title) + self.assertEqual(page.content_subtitle, '') + + def test_13_inheritance_and_ct_tracker(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + page.rawcontent_set.create( + region='sidebar', + ordering=0, + text='Something') + page.rawcontent_set.create( + region='main', + ordering=0, + text='Anything') + + page2 = Page.objects.get(pk=2) + page2.rawcontent_set.create( + region='main', + ordering=0, + text='Something else') + page2.rawcontent_set.create( + region='main', + ordering=1, + text='Whatever') + + # Set default, non-caching content proxy + page2.content_proxy_class = ContentProxy + + if hasattr(self, 'assertNumQueries'): + # 4 queries: Two to get the content types of page and page2, one to + # fetch all ancestor PKs of page2 and one to materialize the RawContent + # instances belonging to page's sidebar and page2's main. + self.assertNumQueries(4, lambda: [page2.content.main, page2.content.sidebar]) + self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) + + self.assertEqual(u''.join(c.render() for c in page2.content.main), + 'Something elseWhatever') + self.assertEqual(page2.content.sidebar[0].render(), 'Something') + + page2 = Page.objects.get(pk=2) + self.assertEqual(page2._ct_inventory, {}) + + # Prime Django content type cache + for ct in Page._feincms_content_types: + ContentType.objects.get_for_model(ct) + + if hasattr(self, 'assertNumQueries'): + # 5 queries: Two to get the content types of page and page2, one to + # fetch all ancestor PKs of page2 and one to materialize the RawContent + # instances belonging to page's sidebar and page2's main and a few + # queries to update the pages _ct_inventory attributes: + # - one update to update page2 + # - one update to clobber the _ct_inventory attribute of all descendants + # of page2 + self.assertNumQueries(5, lambda: [page2.content.main, page2.content.sidebar]) + self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) + + self.assertEqual(page2.content.sidebar[0].render(), 'Something') + + # Reload, again, to test ct_tracker extension + page2 = Page.objects.get(pk=2) + + if hasattr(self, 'assertNumQueries'): + self.assertNumQueries(1, lambda: [page2.content.main, page2.content.sidebar]) + + self.assertNotEqual(page2._ct_inventory, {}) + + def test_14_richtext(self): + # only create the content type to test the item editor + # customization hooks + tmp = Page._feincms_content_types[:] + type = Page.create_content_type(RichTextContent, regions=('notexists',)) + Page._feincms_content_types = tmp + + from django.utils.safestring import SafeData + obj = type() + obj.text = 'Something' + self.assertTrue(isinstance(obj.render(), SafeData)) + + def test_15_frontend_editing(self): + self.create_default_page_set() + page = Page.objects.get(pk=1) + self.create_pagecontent(page) + + # this should return a 404 + self.is_published('/admin/page/page/10|rawcontent|1/', should_be=False) + self.is_published('/admin/page/page/1|rawcontent|10/', should_be=False) + + self.assertEqual(self.client.get('/admin/page/page/1|rawcontent|1/').status_code, 200) + self.assertEqual(self.client.post('/admin/page/page/1|rawcontent|1/', { + 'rawcontent-text': 'blablabla', + }).status_code, 200) + + self.assertEqual(page.content.main[0].render(), 'blablabla') + self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') + + request = Empty() + request.session = {'frontend_editing': True} + + self.assertTrue('class="fe_box"' in\ + page.content.main[0].fe_render(request=request)) + + self.assertFalse('class="fe_box"' in self.client.get(page.get_absolute_url() + '?frontend_editing=1').content) + + def test_16_template_tags(self): + # Directly testing template tags doesn't make any sense since + # feincms_render_* do not use simple_tag anymore + pass + + def test_17_page_template_tags(self): + self.create_default_page_set() + + page1 = Page.objects.get(pk=1) + page2 = Page.objects.get(pk=2) + + page2.language = 'de' + page2.translation_of = page1 + page2.active = True + page2.in_navigation = True + page2.save() + + page3 = Page.objects.create(parent=page2, + title='page3', + slug='page3', + language='en', + active=True, + in_navigation=True, + publication_date=datetime(2001, 1, 1), + ) + + # reload these two, their mptt attributes have changed + page1 = Page.objects.get(pk=1) + page2 = Page.objects.get(pk=2) + + context = template.Context({'feincms_page': page2, 'page3': page3}) + + t = template.Template('{% load feincms_page_tags %}{% feincms_parentlink of feincms_page level=1 %}') + self.assertEqual(t.render(context), '/test-page/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for feincms_page as links %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), 'en:/test-page/,de:/test-page/test-child-page/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for page3 as links %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), 'en:/test-page/test-child-page/page3/,de:None') + + t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for page3 as links existing %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), 'en:/test-page/test-child-page/page3/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for feincms_page as links excludecurrent=1 %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), 'en:/test-page/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), '') + + # XXX should the other template tags not respect the in_navigation setting too? + page1.active = True + page1.in_navigation = True + page1.save() + + self.assertEqual(t.render(context), '/test-page/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), '/test-page/test-child-page/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of request as nav level=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + from django.http import HttpRequest + request = HttpRequest() + request.path = '/test-page/' + self.assertEqual(t.render(template.Context({'request': request})), '/test-page/test-child-page/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=99 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), '') + + t = template.Template('{% load feincms_page_tags %}{% feincms_breadcrumbs feincms_page %}') + rendered = t.render(context) + self.assertTrue("Test child page" in rendered) + self.assertTrue('href="/test-page/">Test page' in rendered, msg="The parent page should be a breadcrumb link") + self.assertTrue('href="/test-page/test-child-page/"' not in rendered, msg="The current page should not be a link in the breadcrumbs") + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), '/test-page/test-child-page/,/test-page/test-child-page/page3/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=3 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/,/test-page/test-child-page/page3/') + + t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=3,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual(t.render(context), '/test-page/test-child-page/page3/') + + t = template.Template('{% load feincms_page_tags %}{% if feincms_page|is_parent_of:page3 %}yes{% endif %}|{% if page3|is_parent_of:feincms_page %}yes{% endif %}') + self.assertEqual(t.render(context), 'yes|') + + t = template.Template('{% load feincms_page_tags %}{% if feincms_page|is_equal_or_parent_of:page3 %}yes{% endif %}|{% if page3|is_equal_or_parent_of:feincms_page %}yes{% endif %}') + self.assertEqual(t.render(context), 'yes|') + + t = template.Template('{% load feincms_page_tags %}{% feincms_translatedpage for feincms_page as t1 language=de %}{% feincms_translatedpage for feincms_page as t2 %}{{ t1.id }}|{{ t2.id }}') + self.assertEqual(t.render(context), '2|1') + + def test_17_feincms_navigation(self): + """ + Test feincms_navigation some more + """ + + self.login() + + self.create_page('Page 1') # 1 + self.create_page('Page 1.1', 1) + self.create_page('Page 1.2', 1) # 3 + self.create_page('Page 1.2.1', 3) + self.create_page('Page 1.2.2', 3) + self.create_page('Page 1.2.3', 3) + self.create_page('Page 1.3', 1) + + self.create_page('Page 2') # 8 + self.create_page('Page 2.1', 8) + self.create_page('Page 2.2', 8) + self.create_page('Page 2.3', 8) + + self.create_page('Page 3') # 12 + self.create_page('Page 3.1', 12) + self.create_page('Page 3.2', 12) + self.create_page('Page 3.3', 12) # 15 + self.create_page('Page 3.3.1', 15) # 16 + self.create_page('Page 3.3.1.1', 16) + self.create_page('Page 3.3.2', 15) + + self.create_page('Page 4') # 19 + self.create_page('Page 4.1', 19) + self.create_page('Page 4.2', 19) + + """ + Creates the following structure: + + 1 (1) -+- 1.1 (2) + +- 1.2 (3) -+- 1.2.1 (4) + | +- 1.2.2 (5) + | +- 1.2.3 (6) + +- 1.3 (7) + + 2 (8) -+- 2.1 (9) + +- 2.2 (10) + +- 2.3 (11) + + 3 (12) -+- 3.1 (13) + +- 3.2 (14) + +- 3.3 (15) -+- 3.3.1 (16) --- 3.3.1.1 (17) + +- 3.3.2 (18) + 4 (19) -+- 4.1 (20) + +- 4.2 (21) + """ + + Page.objects.all().update(active=True, in_navigation=True) + Page.objects.filter(id__in=(5, 9, 19)).update(in_navigation=False) + + tests = [ + ( + {'feincms_page': Page.objects.get(pk=1)}, + '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', + ), + ( + {'feincms_page': Page.objects.get(pk=14)}, + '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-332/', + ), + ( + {'feincms_page': Page.objects.get(pk=14)}, + '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=3 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-331/page-3311/,/page-3/page-33/page-332/', + ), + ( + {'feincms_page': Page.objects.get(pk=19)}, + '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', + ), + ] + + for c, t, r in tests: + self.assertEqual( + template.Template(t).render(template.Context(c)), + r) + + # Test that navigation entries do not exist several times, even with + # navigation extensions. Apply the PassthroughExtension to a page + # which does only have direct children, because it does not collect + # pages further down the tree. + page = Page.objects.get(pk=8) + page.navigation_extension = 'tests.testapp.navigation_extensions.PassthroughExtension' + page.save() + + for c, t, r in tests: + self.assertEqual( + template.Template(t).render(template.Context(c)), + r) + + # Now check that disabling a page also disables it in Navigation: + p = Page.objects.get(pk=15) + tmpl = '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=3 %}{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %}' + + data = template.Template(tmpl).render(template.Context({'feincms_page': p})), + self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") + + p.active = False + p.save() + data = template.Template(tmpl).render(template.Context({'feincms_page': p})), + self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") + + def test_18_default_render_method(self): + """ + Test the default render() behavior of selecting render_ methods + to do the (not so) heavy lifting. + """ + + class Something(models.Model): + class Meta: + abstract = True + + def render_main(self): + return u'Hello' + + # do not register this model in the internal FeinCMS bookkeeping structures + tmp = Page._feincms_content_types[:] + type = Page.create_content_type(Something, regions=('notexists',)) + Page._feincms_content_types = tmp + + s = type(region='main', ordering='1') + + self.assertEqual(s.render(), 'Hello') + + def test_19_page_manager(self): + self.create_default_page_set() + + page = Page.objects.get(pk=2) + page.active = True + page.save() + + self.assertEqual(page, Page.objects.page_for_path(page.get_absolute_url())) + self.assertEqual(page, Page.objects.best_match_for_path(page.get_absolute_url() + 'something/hello/')) + + self.assertRaises(Http404, lambda: Page.objects.best_match_for_path('/blabla/blabla/', raise404=True)) + self.assertRaises(Http404, lambda: Page.objects.page_for_path('/asdf/', raise404=True)) + self.assertRaises(Page.DoesNotExist, lambda: Page.objects.best_match_for_path('/blabla/blabla/')) + self.assertRaises(Page.DoesNotExist, lambda: Page.objects.page_for_path('/asdf/')) + + request = Empty() + request.path = request.path_info = page.get_absolute_url() + request.method = 'GET' + request.get_full_path = lambda: '/xyz/' + request.GET = {} + request.META = {} + request.user = AnonymousUser() + + # tadaa + from django.utils import translation + translation.activate(page.language) + + page.active = False + page.save() + + self.assertRaises(Http404, lambda: Page.objects.for_request(request, raise404=True)) + + page.active = True + page.save() + + self.assertRaises(Http404, lambda: Page.objects.for_request(request, raise404=True)) + + page.parent.active = True + page.parent.save() + self.assertEqual(page, Page.objects.for_request(request)) + + old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH + request.path += 'hello/' + + feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = False + self.assertEqual(self.client.get(request.path).status_code, 404) + + feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True + self.assertEqual(self.client.get(request.path).status_code, 200) + self.assertEqual(page, Page.objects.for_request(request, best_match=True)) + + feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old + + page_id = id(request._feincms_page) + p = Page.objects.for_request(request) + self.assertEqual(id(p), page_id) + + def test_20_redirects(self): + self.create_default_page_set() + page1 = Page.objects.get(pk=1) + page2 = Page.objects.get(pk=2) + + page2.active = True + page2.publication_date = datetime.now() - timedelta(days=1) + page2.override_url = '/blablabla/' + page2.redirect_to = page1.get_absolute_url() + page2.save() + + # regenerate cached URLs in the whole tree + page1.active = True + page1.save() + + page2 = Page.objects.get(pk=2) + + # page2 has been modified too, but its URL should not have changed + try: + self.assertRedirects(self.client.get('/blablabla/'), page1.get_absolute_url()) + except TemplateDoesNotExist, e: + # catch the error from rendering page1 + if e.args != ('feincms_base.html',): + raise + + def test_21_copy_content(self): + self.create_default_page_set() + page = Page.objects.get(pk=1) + self.create_pagecontent(page) + + page2 = Page.objects.get(pk=2) + page2.copy_content_from(page) + self.assertEqual(len(page2.content.main), 1) + + def test_22_contactform(self): + self.create_default_page_set() + page = Page.objects.get(pk=1) + page.active = True + page.template_key = 'theother' + page.save() + + page.contactformcontent_set.create(email='mail@example.com', subject='bla', + region='main', ordering=0) + + request = Empty() + request.method = 'GET' + request.GET = {} + request.META = {} + request.user = Empty() + request.user.is_authenticated = lambda: False + request.user.get_and_delete_messages = lambda: () + + page.content.main[0].process(request) + self.assertTrue('form' in page.content.main[0].render(request=request)) + + self.client.post(page.get_absolute_url(), { + 'name': 'So what\'s your name, dude?', + 'email': 'another@example.com', + 'subject': 'This is a test. Please calm down', + 'content': 'Hell on earth.', + }) + + self.assertEquals(len(mail.outbox), 1) + self.assertEquals(mail.outbox[0].subject, 'This is a test. Please calm down') + + def test_23_navigation_extension(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + + self.assertEqual(len(page.extended_navigation()), 0) + + page.navigation_extension = 'tests.testapp.navigation_extensions.PassthroughExtension' + + page2 = Page.objects.get(pk=2) + page2.active = True + page2.in_navigation = True + page2.save() + + self.assertEqual(list(page.extended_navigation()), [page2]) + + page.navigation_extension = 'tests.testapp.navigation_extensions.ThisExtensionDoesNotExist' + + self.assertEqual(len(page.extended_navigation()), 1) + + page.navigation_extension = 'tests.testapp.navigation_extensions.PretenderExtension' + + self.assertEqual(page.extended_navigation()[0].get_absolute_url(), '/asdsa/') + + def test_24_admin_redirects(self): + self.create_default_page_set() + page = Page.objects.get(pk=1) + + response = self.create_pagecontent(page, _continue=1) + self.assertRedirects(response, '/admin/page/page/1/') + + response = self.create_pagecontent(page, _addanother=1) + self.assertRedirects(response, '/admin/page/page/add/') + + response = self.create_pagecontent(page) + self.assertRedirects(response, '/admin/page/page/') + + def test_25_applicationcontent(self): + self.create_default_page_set() + + page1 = Page.objects.get(pk=1) + page1.active = True + page1.save() + + page = Page.objects.get(pk=2) + page.active = True + page.template_key = 'theother' + page.save() + + # Should not be published because the page has no application contents and should + # therefore not catch anything below it. + self.is_published(page1.get_absolute_url() + 'anything/', False) + + page.applicationcontent_set.create( + region='main', ordering=0, + urlconf_path='tests.testapp.applicationcontent_urls') + + self.assertContains(self.client.get(page.get_absolute_url()), + 'module_root') + self.assertContains(self.client.get(page.get_absolute_url() + 'args_test/abc/def/'), + 'abc-def') + self.assertContains(self.client.get(page.get_absolute_url() + 'kwargs_test/abc/def/'), + 'def-abc') + + response = self.client.get(page.get_absolute_url() + 'reverse_test/') + self.assertContains(response, 'home:/test-page/test-child-page/') + self.assertContains(response, 'args:/test-page/test-child-page/args_test/xy/zzy/') + self.assertContains(response, 'base:/test/') + + response = self.client.get(page.get_absolute_url() + 'full_reverse_test/') + self.assertContains(response, 'home:/test-page/test-child-page/') + self.assertContains(response, 'args:/test-page/test-child-page/args_test/xy/zzy/') + self.assertContains(response, 'base:/test/') + + self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), + '/test-page/test-child-page/') + + if hasattr(self, 'assertNumQueries'): + self.assertNumQueries(0, + lambda: reverse('tests.testapp.applicationcontent_urls/ac_module_root')) + + _empty_reverse_cache() + + self.assertNumQueries(1, + lambda: reverse('tests.testapp.applicationcontent_urls/ac_module_root')) + self.assertNumQueries(0, + lambda: reverse('tests.testapp.applicationcontent_urls/ac_module_root')) + + # This should not raise + self.assertEquals(self.client.get(page.get_absolute_url() + 'notexists/').status_code, 404) + + self.assertContains(self.client.get(page.get_absolute_url() + 'fragment/'), + 'some things') + + self.assertRedirects(self.client.get(page.get_absolute_url() + 'redirect/'), + page.get_absolute_url()) + + self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), + page.get_absolute_url()) + + response = self.client.get(page.get_absolute_url() + 'response/') + self.assertContains(response, 'Anything') + self.assertContains(response, '

Main content

') # Ensure response has been wrapped + + # Test standalone behavior + self.assertEqual( + self.client.get(page.get_absolute_url() + 'response/', + HTTP_X_REQUESTED_WITH='XMLHttpRequest').content, + self.client.get(page.get_absolute_url() + 'response_decorated/').content) + + # Test reversing of URLs (with overridden urls too) + page.applicationcontent_set.create( + region='main', + ordering=1, + urlconf_path='tests.testapp.blog_urls') + page1.applicationcontent_set.create( + region='main', + ordering=0, + urlconf_path='whatever') + + response = self.client.get(page.get_absolute_url() + 'alias_reverse_test/') + self.assertContains(response, 'home:/test-page/') + self.assertContains(response, 'args:/test-page/args_test/xy/zzy/') + self.assertContains(response, 'base:/test/') + + self.assertEqual(reverse('tests.testapp.blog_urls/blog_entry_list'), '/test-page/test-child-page/') + self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), + '/test-page/test-child-page/') + self.assertEqual(reverse('whatever/ac_module_root'), '/test-page/') + + page.applicationcontent_set.get(urlconf_path='tests.testapp.applicationcontent_urls').delete() + + self.assertEqual(reverse('tests.testapp.blog_urls/blog_entry_list'), '/test-page/test-child-page/') + self.assertEqual(reverse('whatever/ac_module_root'), '/test-page/') + + # Ensure ApplicationContent's admin_fields support works properly + self.assertContains(self.client.get('/admin/page/page/%d/' % page.id), + 'exclusive_subpages') + + def test_26_page_form_initial(self): + self.create_default_page_set() + + self.assertEqual(self.client.get('/admin/page/page/add/?translation_of=1&lang=de').status_code, 200) + self.assertEqual(self.client.get('/admin/page/page/add/?parent=1').status_code, 200) + self.assertEqual(self.client.get('/admin/page/page/add/?parent=2').status_code, 200) + + def test_27_cached_url_clash(self): + self.create_default_page_set() + + page1 = Page.objects.get(pk=1) + page2 = Page.objects.get(pk=2) + + page1.override_url = '/' + page1.active = True + page1.save() + + self.assertContains(self.create_pagecontent(page2, active=True, override_url='/'), + 'already taken by') + + def test_28_applicationcontent_reverse(self): + self.create_default_page_set() + page1 = Page.objects.get(pk=1) + page1.active = True + page1.save() + + page = Page.objects.get(pk=2) + page.active = True + page.template_key = 'theother' + page.save() + page.applicationcontent_set.create( + region='main', ordering=0, + urlconf_path='tests.testapp.applicationcontent_urls') + + from feincms.content.application.models import app_reverse, reverse + + # test app_reverse + self.assertEqual(app_reverse('ac_module_root', 'tests.testapp.applicationcontent_urls'), + page.get_absolute_url()) + + # test reverse replacement - should still work, but is deprecated + self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), + page.get_absolute_url()) + + # when specific applicationcontent exists more then once reverse should return url + # for the one that has tree_id same as current feincms page + self.create_page(title='Home DE', language='de', active=True) + page_de = Page.objects.get(title='Home DE') + self.create_page(title='Child 1 DE', language='de', parent=page_de.id, active=True) + page_de_1 = Page.objects.get(title='Child 1 DE') + page_de_1.applicationcontent_set.create( + region='main', ordering=0, + urlconf_path='tests.testapp.applicationcontent_urls') + _empty_reverse_cache() + + settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), 'templates'),) + self.client.get(page_de_1.get_absolute_url()) + self.assertEqual(app_reverse('ac_module_root', 'tests.testapp.applicationcontent_urls'), + page_de_1.get_absolute_url()) + + self.client.get(page1.get_absolute_url()) + self.assertEqual(app_reverse('ac_module_root', 'tests.testapp.applicationcontent_urls'), + page.get_absolute_url()) + + def test_29_medialibrary_admin(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + + mediafile = MediaFile.objects.create(file='somefile.jpg') + page.mediafilecontent_set.create( + mediafile=mediafile, + region='main', + position='block', + ordering=1) + + self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), 'somefile.jpg') + + import zipfile + zf = zipfile.ZipFile('test.zip', 'w') + for i in range(10): + zf.writestr('test%d.jpg' % i, 'test%d' % i) + zf.close() + + self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/mediafile-bulk-upload/', { + 'data': open('test.zip'), + }), '/admin/medialibrary/mediafile/') + + self.assertEqual(MediaFile.objects.count(), 11, "Upload of media files with ZIP does not work") + + self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/add/', { + 'file': open(os.path.join(os.path.dirname(os.path.dirname(__file__)), + 'docs', 'images', 'tree_editor.png')), + 'translations-TOTAL_FORMS': 0, + 'translations-INITIAL_FORMS': 0, + 'translations-MAX_NUM_FORMS': 10, + }), '/admin/medialibrary/mediafile/') + + self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), + '100x100.png" alt="" />') + + stats = list(MediaFile.objects.values_list('type', flat=True)) + self.assertEqual(stats.count('image'), 2) + self.assertEqual(stats.count('other'), 10) + + def test_30_context_processors(self): + self.create_default_page_set() + Page.objects.update(active=True, in_navigation=True) + + request = Empty() + request.GET = {} + request.META = {} + request.method = 'GET' + request.path = request.path_info = '/test-page/test-child-page/abcdef/' + request.get_full_path = lambda: '/test-page/test-child-page/abcdef/' + + ctx = add_page_if_missing(request) + self.assertEqual(ctx['feincms_page'], request._feincms_page) + + def test_31_sites_framework_associating_with_single_site(self): + self.login() + site_2 = Site.objects.create(name='site 2', domain='2.example.com') + self.create_page('site 1 homepage', override_url='/', active=True) + self.create_page('site 2 homepage', override_url='/', + site=site_2.id, active=True) + self.assertEqual(Page.objects.count(), 2) + self.assertEqual(Page.objects.active().count(), 1) + + def test_32_applicationcontent_inheritance20(self): + self.create_default_page_set() + + page1 = Page.objects.get(pk=1) + page1.active = True + page1.save() + + page = Page.objects.get(pk=2) + page.active = True + page.template_key = 'theother' + page.save() + + # Should not be published because the page has no application contents and should + # therefore not catch anything below it. + self.is_published(page1.get_absolute_url() + 'anything/', False) + + page.applicationcontent_set.create( + region='main', ordering=0, + urlconf_path='tests.testapp.applicationcontent_urls') + page.rawcontent_set.create( + region='main', ordering=1, text='some_main_region_text') + page.rawcontent_set.create( + region='sidebar', ordering=0, text='some_sidebar_region_text') + + self.assertContains(self.client.get(page.get_absolute_url()), + 'module_root') + + response = self.client.get(page.get_absolute_url() + 'inheritance20/') + self.assertContains(response, 'a content 42') + self.assertContains(response, 'b content') + self.assertNotContains(response, 'some_main_region_text') + self.assertContains(response, 'some_sidebar_region_text') + self.assertNotContains(response, 'some content outside') + + def test_33_preview(self): + self.create_default_page_set() + page = Page.objects.get(pk=1) + page.template_key = 'theother' + page.save() + page.rawcontent_set.create( + region='main', + ordering=0, + text='Example content') + + self.assertEquals(self.client.get(page.get_absolute_url()).status_code, 404) + self.assertContains(self.client.get('%s_preview/%s/' % (page.get_absolute_url(), page.pk)), + 'Example content') + + def test_34_access(self): + self.create_default_page_set() + + page = Page.objects.get(pk=1) + page.override_url = '/something/' + page.save() + + Page.objects.update(active=True) + + self.create_page(title='redirect page', override_url='/', redirect_to=page.get_absolute_url(), active=True) + + # / -> redirect to /something/ + r = self.client.get('/') + self.assertRedirects(r, page.get_absolute_url()) + # /something/ should work + r = self.client.get(page.override_url) + self.assertEquals(r.status_code, 200) + # /foo not existant -> 404 + r = self.client.get('/foo/') + self.assertEquals(r.status_code, 404) + + def test_35_access_with_extra_path(self): + self.login() + self.create_page(title='redirect again', override_url='/', redirect_to='/somewhere/', active=True) + self.create_page(title='somewhere', active=True) + + r = self.client.get('/') + self.assertRedirects(r, '/somewhere/') + r = self.client.get('/dingdong/') + self.assertEquals(r.status_code, 404) + + old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH + feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True + + r = self.client.get('/') + self.assertRedirects(r, '/somewhere/') + r = self.client.get('/dingdong/') + self.assertEquals(r.status_code, 404) + + feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old diff --git a/tests/tests/tests.py b/tests/tests/tests.py index 9363c0e61..2d37987e7 100644 --- a/tests/tests/tests.py +++ b/tests/tests/tests.py @@ -105,1267 +105,6 @@ class ExampleCMSBase2(Base): Page.register_response_processor(processors.debug_sql_queries_response_processor()) -class PagesTestCase(TestCase): - def setUp(self): - u = User(username='test', is_active=True, is_staff=True, is_superuser=True) - u.set_password('test') - u.save() - - self.site_1 = Site.objects.all()[0] - - Page.register_templates({ - 'key': 'base', - 'title': 'Standard template', - 'path': 'feincms_base.html', - 'regions': ( - ('main', 'Main content area'), - ('sidebar', 'Sidebar', 'inherited'), - ), - }, { - 'key': 'theother', - 'title': 'This actually exists', - 'path': 'base.html', - 'regions': ( - ('main', 'Main content area'), - ('sidebar', 'Sidebar', 'inherited'), - ), - }) - - def login(self): - self.assertTrue(self.client.login(username='test', password='test')) - - def create_page(self, title='Test page', parent='', **kwargs): - dic = { - 'title': title, - 'slug': kwargs.get('slug', slugify(title)), - 'parent': parent, - 'template_key': 'base', - 'publication_date_0': '2009-01-01', - 'publication_date_1': '00:00:00', - 'initial-publication_date_0': '2009-01-01', - 'initial-publication_date_1': '00:00:00', - 'language': 'en', - 'site': self.site_1.id, - - 'rawcontent_set-TOTAL_FORMS': 0, - 'rawcontent_set-INITIAL_FORMS': 0, - 'rawcontent_set-MAX_NUM_FORMS': 10, - - 'mediafilecontent_set-TOTAL_FORMS': 0, - 'mediafilecontent_set-INITIAL_FORMS': 0, - 'mediafilecontent_set-MAX_NUM_FORMS': 10, - - 'imagecontent_set-TOTAL_FORMS': 0, - 'imagecontent_set-INITIAL_FORMS': 0, - 'imagecontent_set-MAX_NUM_FORMS': 10, - - 'contactformcontent_set-TOTAL_FORMS': 0, - 'contactformcontent_set-INITIAL_FORMS': 0, - 'contactformcontent_set-MAX_NUM_FORMS': 10, - - 'filecontent_set-TOTAL_FORMS': 0, - 'filecontent_set-INITIAL_FORMS': 0, - 'filecontent_set-MAX_NUM_FORMS': 10, - - 'applicationcontent_set-TOTAL_FORMS': 0, - 'applicationcontent_set-INITIAL_FORMS': 0, - 'applicationcontent_set-MAX_NUM_FORMS': 10, - } - dic.update(kwargs) - return self.client.post('/admin/page/page/add/', dic) - - def create_default_page_set(self): - self.login() - self.create_page() - return self.create_page('Test child page', 1) - - def is_published(self, url, should_be=True): - try: - self.client.get(url) - except TemplateDoesNotExist, e: - if should_be: - if e.args != ('feincms_base.html',): - raise - else: - if e.args != ('404.html',): - raise - - def test_01_tree_editor(self): - self.login() - self.assertEqual(self.client.get('/admin/page/page/').status_code, 200) - - self.assertRedirects(self.client.get('/admin/page/page/?anything=anything'), - '/admin/page/page/?e=1') - - def test_02_add_page(self): - self.login() - self.assertRedirects(self.create_page(title='Test page ' * 10, slug='test-page'), - '/admin/page/page/') - self.assertEqual(Page.objects.count(), 1) - self.assertContains(self.client.get('/admin/page/page/'), '…') - - def test_03_item_editor(self): - self.login() - self.assertRedirects(self.create_page(_continue=1), '/admin/page/page/1/') - self.assertEqual(self.client.get('/admin/page/page/1/').status_code, 200) - self.is_published('/admin/page/page/42/', should_be=False) - - def test_03_add_another(self): - self.login() - self.assertRedirects(self.create_page(_addanother=1), '/admin/page/page/add/') - - def test_04_add_child(self): - response = self.create_default_page_set() - self.assertRedirects(response, '/admin/page/page/') - self.assertEqual(Page.objects.count(), 2) - - page = Page.objects.get(pk=2) - self.assertEqual(page.get_absolute_url(), '/test-page/test-child-page/') - - page.active = True - page.in_navigation = True - page.save() - - # page2 inherited the inactive flag from the toplevel page - self.assertContains(self.client.get('/admin/page/page/'), 'inherited') - - page1 = Page.objects.get(pk=1) - page1.active = True - page1.save() - - self.assertEqual(len(self.client.get('/admin/page/page/').content.split('checked="checked"')), 4) - - def test_05_override_url(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - page.override_url = '/something/' - page.save() - - page2 = Page.objects.get(pk=2) - self.assertEqual(page2.get_absolute_url(), '/something/test-child-page/') - - page.override_url = '/' - page.save() - page2 = Page.objects.get(pk=2) - self.assertEqual(page2.get_absolute_url(), '/test-child-page/') - - # This goes through feincms.views.base.handler instead of the applicationcontent handler - self.is_published('/', False) - page.active = True - page.template_key = 'theother' - page.save() - self.is_published('/', True) - - def test_06_tree_editor_save(self): - self.create_default_page_set() - - page1 = Page.objects.get(pk=1) - page2 = Page.objects.get(pk=2) - - page3 = Page.objects.create(title='page3', slug='page3', parent=page2) - page4 = Page.objects.create(title='page4', slug='page4', parent=page1) - page5 = Page.objects.create(title='page5', slug='page5', parent=None) - - self.assertEqual(page3.get_absolute_url(), '/test-page/test-child-page/page3/') - self.assertEqual(page4.get_absolute_url(), '/test-page/page4/') - self.assertEqual(page5.get_absolute_url(), '/page5/') - - self.client.post('/admin/page/page/', { - '__cmd': 'move_node', - 'position': 'last-child', - 'cut_item': '1', - 'pasted_on': '5', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - self.assertEqual(Page.objects.get(pk=1).get_absolute_url(), - '/page5/test-page/') - self.assertEqual(Page.objects.get(pk=5).get_absolute_url(), - '/page5/') - self.assertEqual(Page.objects.get(pk=3).get_absolute_url(), - '/page5/test-page/test-child-page/page3/') - - def test_07_tree_editor_toggle_boolean(self): - self.create_default_page_set() - - self.assertEqual(Page.objects.get(pk=1).in_navigation, False) - - self.assertContains(self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'in_navigation', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), - r'checked=\"checked\"') - self.assertEqual(Page.objects.get(pk=1).in_navigation, True) - self.assertNotContains(self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'in_navigation', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), - 'checked="checked"') - self.assertEqual(Page.objects.get(pk=1).in_navigation, False) - - self.assertTrue(isinstance(self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'notexists', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), HttpResponseBadRequest)) - - def test_07_tree_editor_invalid_ajax(self): - self.login() - self.assertContains(self.client.post('/admin/page/page/', { - '__cmd': 'notexists', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), - 'Oops. AJAX request not understood.', - status_code=400) - - def test_08_publishing(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - page2 = Page.objects.get(pk=2) - self.is_published(page.get_absolute_url(), should_be=False) - self.is_published(page2.get_absolute_url(), should_be=False) - - page.active = True - page.save() - page2.active = True - page2.save() - self.is_published(page.get_absolute_url(), should_be=True) - self.is_published(page2.get_absolute_url(), should_be=True) - - old_publication = page.publication_date - page.publication_date = datetime.now() + timedelta(days=1) - page.save() - self.is_published(page.get_absolute_url(), should_be=False) - - # Should be not accessible because of its parent's inactivity - self.is_published(page2.get_absolute_url(), should_be=False) - - page.publication_date = old_publication - page.publication_end_date = datetime.now() - timedelta(days=1) - page.save() - self.is_published(page.get_absolute_url(), should_be=False) - - # Should be not accessible because of its parent's inactivity - self.is_published(page2.get_absolute_url(), should_be=False) - - page.publication_end_date = datetime.now() + timedelta(days=1) - page.save() - self.is_published(page.get_absolute_url(), should_be=True) - self.is_published(page2.get_absolute_url(), should_be=True) - - def create_pagecontent(self, page, **kwargs): - data = { - 'title': page.title, - 'slug': page.slug, - #'parent': page.parent_id, # this field is excluded from the form - 'template_key': page.template_key, - 'publication_date_0': '2009-01-01', - 'publication_date_1': '00:00:00', - 'initial-publication_date_0': '2009-01-01', - 'initial-publication_date_1': '00:00:00', - 'language': 'en', - 'site': self.site_1.id, - - 'rawcontent_set-TOTAL_FORMS': 1, - 'rawcontent_set-INITIAL_FORMS': 0, - 'rawcontent_set-MAX_NUM_FORMS': 10, - - 'rawcontent_set-0-parent': 1, - 'rawcontent_set-0-region': 'main', - 'rawcontent_set-0-ordering': 0, - 'rawcontent_set-0-text': 'This is some example content', - - 'mediafilecontent_set-TOTAL_FORMS': 1, - 'mediafilecontent_set-INITIAL_FORMS': 0, - 'mediafilecontent_set-MAX_NUM_FORMS': 10, - - 'mediafilecontent_set-0-parent': 1, - 'mediafilecontent_set-0-position': 'block', - - 'imagecontent_set-TOTAL_FORMS': 1, - 'imagecontent_set-INITIAL_FORMS': 0, - 'imagecontent_set-MAX_NUM_FORMS': 10, - - 'imagecontent_set-0-parent': 1, - 'imagecontent_set-0-position': 'default', - - 'contactformcontent_set-TOTAL_FORMS': 1, - 'contactformcontent_set-INITIAL_FORMS': 0, - 'contactformcontent_set-MAX_NUM_FORMS': 10, - - 'filecontent_set-TOTAL_FORMS': 1, - 'filecontent_set-INITIAL_FORMS': 0, - 'filecontent_set-MAX_NUM_FORMS': 10, - - 'applicationcontent_set-TOTAL_FORMS': 1, - 'applicationcontent_set-INITIAL_FORMS': 0, - 'applicationcontent_set-MAX_NUM_FORMS': 10, - } - data.update(kwargs) - - return self.client.post('/admin/page/page/%s/' % page.pk, data) - - def test_09_pagecontent(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - response = self.create_pagecontent(page) - self.assertRedirects(response, '/admin/page/page/') - self.assertEqual(page.content.main[0].__class__.__name__, 'RawContent') - - page2 = Page.objects.get(pk=2) - page2.symlinked_page = page - - # Test that all_of_type works correctly even before accessing - # other content methods - self.assertEqual(len(page2.content.all_of_type(RawContent)), 1) - - self.assertEqual(page2.content.main[0].__class__.__name__, 'RawContent') - self.assertEqual(unicode(page2.content.main[0]), - 'main on Test page, ordering 0') - - self.assertEqual(len(page2.content.main), 1) - self.assertEqual(len(page2.content.sidebar), 0) - self.assertEqual(len(page2.content.nonexistant_region), 0) - - self.assertTrue(isinstance(page2.content.media, forms.Media)) - - self.assertEqual(len(page2.content.all_of_type(RawContent)), 1) - self.assertEqual(len(page2.content.all_of_type((ImageContent,))), 0) - self.assertEqual(len(page2.content.all_of_type([ImageContent])), 0) - - def test_10_mediafile_and_imagecontent(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - self.create_pagecontent(page) - - category = Category.objects.create(title='Category', parent=None) - category2 = Category.objects.create(title='Something', parent=category) - - self.assertEqual(unicode(category2), 'Category - Something') - self.assertEqual(unicode(category), 'Category') - - mediafile = MediaFile.objects.create(file='somefile.jpg') - mediafile.categories = [category] - page.mediafilecontent_set.create( - mediafile=mediafile, - region='main', - position='block', - ordering=1) - - self.assertEqual(unicode(mediafile), 'somefile.jpg') - - mediafile.translations.create(caption='something', - language_code='%s-ha' % short_language_code()) - mediafile.purge_translation_cache() - - self.assertTrue('something' in unicode(mediafile)) - - mf = page.content.main[1].mediafile - - self.assertEqual(mf.translation.caption, 'something') - self.assertEqual(mf.translation.short_language_code(), short_language_code()) - self.assertNotEqual(mf.get_absolute_url(), '') - self.assertEqual(unicode(mf), 'something') - self.assertTrue(mf.type == 'image') - - self.assertEqual(MediaFile.objects.only_language('de').count(), 0) - self.assertEqual(MediaFile.objects.only_language('en').count(), 0) - self.assertEqual(MediaFile.objects.only_language('%s-ha' % short_language_code()).count(), - 1) - - self.assertTrue('%s-ha' % short_language_code() in mf.available_translations) - - # this should not raise - self.client.get('/admin/page/page/1/') - - #self.assertTrue('alt="something"' in page.content.main[1].render()) Since it isn't an image - - page.imagecontent_set.create(image='somefile.jpg', region='main', position='default', ordering=2) - page.filecontent_set.create(file='somefile.jpg', title='thetitle', region='main', ordering=3) - - # Reload page, reset _ct_inventory - page = Page.objects.get(pk=page.pk) - page._ct_inventory = None - - self.assertTrue('somefile.jpg' in page.content.main[2].render()) - self.assertTrue(re.search('.*thetitle.*', page.content.main[3].render(), re.MULTILINE + re.DOTALL) is not None) - - page.mediafilecontent_set.update(mediafile=3) - # this should not raise - self.client.get('/admin/page/page/1/') - - field = MediaFile._meta.get_field('file') - old = (field.upload_to, field.storage, field.generate_filename) - from django.core.files.storage import FileSystemStorage - MediaFile.reconfigure(upload_to=lambda: 'anywhere', - storage=FileSystemStorage(location='/wha/', base_url='/whe/')) - mediafile = MediaFile.objects.get(pk=1) - self.assertEqual(mediafile.file.url, '/whe/somefile.jpg') - - # restore settings - (field.upload_to, field.storage, field.generate_filename) = old - - mediafile = MediaFile.objects.get(pk=1) - self.assertEqual(mediafile.file.url, 'somefile.jpg') - - def test_11_translations(self): - self.create_default_page_set() - - page1 = Page.objects.get(pk=1) - self.assertEqual(len(page1.available_translations()), 0) - - page1 = Page.objects.get(pk=1) - page2 = Page.objects.get(pk=2) - - page2.language = 'de' - page2.save() - - self.assertEqual(len(page2.available_translations()), 0) - - page2.translation_of = page1 - page2.save() - - self.assertEqual(len(page2.available_translations()), 1) - self.assertEqual(len(page1.available_translations()), 1) - - self.assertEqual(page1, page1.original_translation) - self.assertEqual(page1, page2.original_translation) - - def test_12_titles(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - - self.assertEqual(page.page_title, page.title) - self.assertEqual(page.content_title, page.title) - - page._content_title = 'Something\nawful' - page._page_title = 'Hello world' - page.save() - - self.assertEqual(page.page_title, 'Hello world') - self.assertEqual(page.content_title, 'Something') - self.assertEqual(page.content_subtitle, 'awful') - - page._content_title = 'Only one line' - self.assertEqual(page.content_title, 'Only one line') - self.assertEqual(page.content_subtitle, '') - - page._content_title = '' - self.assertEqual(page.content_title, page.title) - self.assertEqual(page.content_subtitle, '') - - def test_13_inheritance_and_ct_tracker(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - page.rawcontent_set.create( - region='sidebar', - ordering=0, - text='Something') - page.rawcontent_set.create( - region='main', - ordering=0, - text='Anything') - - page2 = Page.objects.get(pk=2) - page2.rawcontent_set.create( - region='main', - ordering=0, - text='Something else') - page2.rawcontent_set.create( - region='main', - ordering=1, - text='Whatever') - - # Set default, non-caching content proxy - page2.content_proxy_class = ContentProxy - - if hasattr(self, 'assertNumQueries'): - # 4 queries: Two to get the content types of page and page2, one to - # fetch all ancestor PKs of page2 and one to materialize the RawContent - # instances belonging to page's sidebar and page2's main. - self.assertNumQueries(4, lambda: [page2.content.main, page2.content.sidebar]) - self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) - - self.assertEqual(u''.join(c.render() for c in page2.content.main), - 'Something elseWhatever') - self.assertEqual(page2.content.sidebar[0].render(), 'Something') - - page2 = Page.objects.get(pk=2) - self.assertEqual(page2._ct_inventory, {}) - - # Prime Django content type cache - for ct in Page._feincms_content_types: - ContentType.objects.get_for_model(ct) - - if hasattr(self, 'assertNumQueries'): - # 5 queries: Two to get the content types of page and page2, one to - # fetch all ancestor PKs of page2 and one to materialize the RawContent - # instances belonging to page's sidebar and page2's main and a few - # queries to update the pages _ct_inventory attributes: - # - one update to update page2 - # - one update to clobber the _ct_inventory attribute of all descendants - # of page2 - self.assertNumQueries(5, lambda: [page2.content.main, page2.content.sidebar]) - self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) - - self.assertEqual(page2.content.sidebar[0].render(), 'Something') - - # Reload, again, to test ct_tracker extension - page2 = Page.objects.get(pk=2) - - if hasattr(self, 'assertNumQueries'): - self.assertNumQueries(1, lambda: [page2.content.main, page2.content.sidebar]) - - self.assertNotEqual(page2._ct_inventory, {}) - - def test_14_richtext(self): - # only create the content type to test the item editor - # customization hooks - tmp = Page._feincms_content_types[:] - type = Page.create_content_type(RichTextContent, regions=('notexists',)) - Page._feincms_content_types = tmp - - from django.utils.safestring import SafeData - obj = type() - obj.text = 'Something' - self.assertTrue(isinstance(obj.render(), SafeData)) - - def test_15_frontend_editing(self): - self.create_default_page_set() - page = Page.objects.get(pk=1) - self.create_pagecontent(page) - - # this should return a 404 - self.is_published('/admin/page/page/10|rawcontent|1/', should_be=False) - self.is_published('/admin/page/page/1|rawcontent|10/', should_be=False) - - self.assertEqual(self.client.get('/admin/page/page/1|rawcontent|1/').status_code, 200) - self.assertEqual(self.client.post('/admin/page/page/1|rawcontent|1/', { - 'rawcontent-text': 'blablabla', - }).status_code, 200) - - self.assertEqual(page.content.main[0].render(), 'blablabla') - self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') - - request = Empty() - request.session = {'frontend_editing': True} - - self.assertTrue('class="fe_box"' in\ - page.content.main[0].fe_render(request=request)) - - self.assertFalse('class="fe_box"' in self.client.get(page.get_absolute_url() + '?frontend_editing=1').content) - - def test_16_template_tags(self): - # Directly testing template tags doesn't make any sense since - # feincms_render_* do not use simple_tag anymore - pass - - def test_17_page_template_tags(self): - self.create_default_page_set() - - page1 = Page.objects.get(pk=1) - page2 = Page.objects.get(pk=2) - - page2.language = 'de' - page2.translation_of = page1 - page2.active = True - page2.in_navigation = True - page2.save() - - page3 = Page.objects.create(parent=page2, - title='page3', - slug='page3', - language='en', - active=True, - in_navigation=True, - publication_date=datetime(2001, 1, 1), - ) - - # reload these two, their mptt attributes have changed - page1 = Page.objects.get(pk=1) - page2 = Page.objects.get(pk=2) - - context = template.Context({'feincms_page': page2, 'page3': page3}) - - t = template.Template('{% load feincms_page_tags %}{% feincms_parentlink of feincms_page level=1 %}') - self.assertEqual(t.render(context), '/test-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for feincms_page as links %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/,de:/test-page/test-child-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for page3 as links %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/test-child-page/page3/,de:None') - - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for page3 as links existing %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/test-child-page/page3/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for feincms_page as links excludecurrent=1 %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '') - - # XXX should the other template tags not respect the in_navigation setting too? - page1.active = True - page1.in_navigation = True - page1.save() - - self.assertEqual(t.render(context), '/test-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/test-child-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of request as nav level=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - from django.http import HttpRequest - request = HttpRequest() - request.path = '/test-page/' - self.assertEqual(t.render(template.Context({'request': request})), '/test-page/test-child-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=99 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '') - - t = template.Template('{% load feincms_page_tags %}{% feincms_breadcrumbs feincms_page %}') - rendered = t.render(context) - self.assertTrue("Test child page" in rendered) - self.assertTrue('href="/test-page/">Test page' in rendered, msg="The parent page should be a breadcrumb link") - self.assertTrue('href="/test-page/test-child-page/"' not in rendered, msg="The current page should not be a link in the breadcrumbs") - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/test-child-page/,/test-page/test-child-page/page3/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=3 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/,/test-page/test-child-page/page3/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=3,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/test-child-page/page3/') - - t = template.Template('{% load feincms_page_tags %}{% if feincms_page|is_parent_of:page3 %}yes{% endif %}|{% if page3|is_parent_of:feincms_page %}yes{% endif %}') - self.assertEqual(t.render(context), 'yes|') - - t = template.Template('{% load feincms_page_tags %}{% if feincms_page|is_equal_or_parent_of:page3 %}yes{% endif %}|{% if page3|is_equal_or_parent_of:feincms_page %}yes{% endif %}') - self.assertEqual(t.render(context), 'yes|') - - t = template.Template('{% load feincms_page_tags %}{% feincms_translatedpage for feincms_page as t1 language=de %}{% feincms_translatedpage for feincms_page as t2 %}{{ t1.id }}|{{ t2.id }}') - self.assertEqual(t.render(context), '2|1') - - def test_17_feincms_navigation(self): - """ - Test feincms_navigation some more - """ - - self.login() - - self.create_page('Page 1') # 1 - self.create_page('Page 1.1', 1) - self.create_page('Page 1.2', 1) # 3 - self.create_page('Page 1.2.1', 3) - self.create_page('Page 1.2.2', 3) - self.create_page('Page 1.2.3', 3) - self.create_page('Page 1.3', 1) - - self.create_page('Page 2') # 8 - self.create_page('Page 2.1', 8) - self.create_page('Page 2.2', 8) - self.create_page('Page 2.3', 8) - - self.create_page('Page 3') # 12 - self.create_page('Page 3.1', 12) - self.create_page('Page 3.2', 12) - self.create_page('Page 3.3', 12) # 15 - self.create_page('Page 3.3.1', 15) # 16 - self.create_page('Page 3.3.1.1', 16) - self.create_page('Page 3.3.2', 15) - - self.create_page('Page 4') # 19 - self.create_page('Page 4.1', 19) - self.create_page('Page 4.2', 19) - - """ - Creates the following structure: - - 1 (1) -+- 1.1 (2) - +- 1.2 (3) -+- 1.2.1 (4) - | +- 1.2.2 (5) - | +- 1.2.3 (6) - +- 1.3 (7) - - 2 (8) -+- 2.1 (9) - +- 2.2 (10) - +- 2.3 (11) - - 3 (12) -+- 3.1 (13) - +- 3.2 (14) - +- 3.3 (15) -+- 3.3.1 (16) --- 3.3.1.1 (17) - +- 3.3.2 (18) - 4 (19) -+- 4.1 (20) - +- 4.2 (21) - """ - - Page.objects.all().update(active=True, in_navigation=True) - Page.objects.filter(id__in=(5, 9, 19)).update(in_navigation=False) - - tests = [ - ( - {'feincms_page': Page.objects.get(pk=1)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', - ), - ( - {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-332/', - ), - ( - {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=3 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-331/page-3311/,/page-3/page-33/page-332/', - ), - ( - {'feincms_page': Page.objects.get(pk=19)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', - ), - ] - - for c, t, r in tests: - self.assertEqual( - template.Template(t).render(template.Context(c)), - r) - - # Test that navigation entries do not exist several times, even with - # navigation extensions. Apply the PassthroughExtension to a page - # which does only have direct children, because it does not collect - # pages further down the tree. - page = Page.objects.get(pk=8) - page.navigation_extension = 'tests.testapp.navigation_extensions.PassthroughExtension' - page.save() - - for c, t, r in tests: - self.assertEqual( - template.Template(t).render(template.Context(c)), - r) - - # Now check that disabling a page also disables it in Navigation: - p = Page.objects.get(pk=15) - tmpl = '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=3 %}{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %}' - - data = template.Template(tmpl).render(template.Context({'feincms_page': p})), - self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") - - p.active = False - p.save() - data = template.Template(tmpl).render(template.Context({'feincms_page': p})), - self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") - - def test_18_default_render_method(self): - """ - Test the default render() behavior of selecting render_ methods - to do the (not so) heavy lifting. - """ - - class Something(models.Model): - class Meta: - abstract = True - - def render_main(self): - return u'Hello' - - # do not register this model in the internal FeinCMS bookkeeping structures - tmp = Page._feincms_content_types[:] - type = Page.create_content_type(Something, regions=('notexists',)) - Page._feincms_content_types = tmp - - s = type(region='main', ordering='1') - - self.assertEqual(s.render(), 'Hello') - - def test_19_page_manager(self): - self.create_default_page_set() - - page = Page.objects.get(pk=2) - page.active = True - page.save() - - self.assertEqual(page, Page.objects.page_for_path(page.get_absolute_url())) - self.assertEqual(page, Page.objects.best_match_for_path(page.get_absolute_url() + 'something/hello/')) - - self.assertRaises(Http404, lambda: Page.objects.best_match_for_path('/blabla/blabla/', raise404=True)) - self.assertRaises(Http404, lambda: Page.objects.page_for_path('/asdf/', raise404=True)) - self.assertRaises(Page.DoesNotExist, lambda: Page.objects.best_match_for_path('/blabla/blabla/')) - self.assertRaises(Page.DoesNotExist, lambda: Page.objects.page_for_path('/asdf/')) - - request = Empty() - request.path = request.path_info = page.get_absolute_url() - request.method = 'GET' - request.get_full_path = lambda: '/xyz/' - request.GET = {} - request.META = {} - request.user = AnonymousUser() - - # tadaa - from django.utils import translation - translation.activate(page.language) - - page.active = False - page.save() - - self.assertRaises(Http404, lambda: Page.objects.for_request(request, raise404=True)) - - page.active = True - page.save() - - self.assertRaises(Http404, lambda: Page.objects.for_request(request, raise404=True)) - - page.parent.active = True - page.parent.save() - self.assertEqual(page, Page.objects.for_request(request)) - - old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH - request.path += 'hello/' - - feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = False - self.assertEqual(self.client.get(request.path).status_code, 404) - - feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True - self.assertEqual(self.client.get(request.path).status_code, 200) - self.assertEqual(page, Page.objects.for_request(request, best_match=True)) - - feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old - - page_id = id(request._feincms_page) - p = Page.objects.for_request(request) - self.assertEqual(id(p), page_id) - - def test_20_redirects(self): - self.create_default_page_set() - page1 = Page.objects.get(pk=1) - page2 = Page.objects.get(pk=2) - - page2.active = True - page2.publication_date = datetime.now() - timedelta(days=1) - page2.override_url = '/blablabla/' - page2.redirect_to = page1.get_absolute_url() - page2.save() - - # regenerate cached URLs in the whole tree - page1.active = True - page1.save() - - page2 = Page.objects.get(pk=2) - - # page2 has been modified too, but its URL should not have changed - try: - self.assertRedirects(self.client.get('/blablabla/'), page1.get_absolute_url()) - except TemplateDoesNotExist, e: - # catch the error from rendering page1 - if e.args != ('feincms_base.html',): - raise - - def test_21_copy_content(self): - self.create_default_page_set() - page = Page.objects.get(pk=1) - self.create_pagecontent(page) - - page2 = Page.objects.get(pk=2) - page2.copy_content_from(page) - self.assertEqual(len(page2.content.main), 1) - - def test_22_contactform(self): - self.create_default_page_set() - page = Page.objects.get(pk=1) - page.active = True - page.template_key = 'theother' - page.save() - - page.contactformcontent_set.create(email='mail@example.com', subject='bla', - region='main', ordering=0) - - request = Empty() - request.method = 'GET' - request.GET = {} - request.META = {} - request.user = Empty() - request.user.is_authenticated = lambda: False - request.user.get_and_delete_messages = lambda: () - - page.content.main[0].process(request) - self.assertTrue('form' in page.content.main[0].render(request=request)) - - self.client.post(page.get_absolute_url(), { - 'name': 'So what\'s your name, dude?', - 'email': 'another@example.com', - 'subject': 'This is a test. Please calm down', - 'content': 'Hell on earth.', - }) - - self.assertEquals(len(mail.outbox), 1) - self.assertEquals(mail.outbox[0].subject, 'This is a test. Please calm down') - - def test_23_navigation_extension(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - - self.assertEqual(len(page.extended_navigation()), 0) - - page.navigation_extension = 'tests.testapp.navigation_extensions.PassthroughExtension' - - page2 = Page.objects.get(pk=2) - page2.active = True - page2.in_navigation = True - page2.save() - - self.assertEqual(list(page.extended_navigation()), [page2]) - - page.navigation_extension = 'tests.testapp.navigation_extensions.ThisExtensionDoesNotExist' - - self.assertEqual(len(page.extended_navigation()), 1) - - page.navigation_extension = 'tests.testapp.navigation_extensions.PretenderExtension' - - self.assertEqual(page.extended_navigation()[0].get_absolute_url(), '/asdsa/') - - def test_24_admin_redirects(self): - self.create_default_page_set() - page = Page.objects.get(pk=1) - - response = self.create_pagecontent(page, _continue=1) - self.assertRedirects(response, '/admin/page/page/1/') - - response = self.create_pagecontent(page, _addanother=1) - self.assertRedirects(response, '/admin/page/page/add/') - - response = self.create_pagecontent(page) - self.assertRedirects(response, '/admin/page/page/') - - def test_25_applicationcontent(self): - self.create_default_page_set() - - page1 = Page.objects.get(pk=1) - page1.active = True - page1.save() - - page = Page.objects.get(pk=2) - page.active = True - page.template_key = 'theother' - page.save() - - # Should not be published because the page has no application contents and should - # therefore not catch anything below it. - self.is_published(page1.get_absolute_url() + 'anything/', False) - - page.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='tests.testapp.applicationcontent_urls') - - self.assertContains(self.client.get(page.get_absolute_url()), - 'module_root') - self.assertContains(self.client.get(page.get_absolute_url() + 'args_test/abc/def/'), - 'abc-def') - self.assertContains(self.client.get(page.get_absolute_url() + 'kwargs_test/abc/def/'), - 'def-abc') - - response = self.client.get(page.get_absolute_url() + 'reverse_test/') - self.assertContains(response, 'home:/test-page/test-child-page/') - self.assertContains(response, 'args:/test-page/test-child-page/args_test/xy/zzy/') - self.assertContains(response, 'base:/test/') - - response = self.client.get(page.get_absolute_url() + 'full_reverse_test/') - self.assertContains(response, 'home:/test-page/test-child-page/') - self.assertContains(response, 'args:/test-page/test-child-page/args_test/xy/zzy/') - self.assertContains(response, 'base:/test/') - - self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), - '/test-page/test-child-page/') - - if hasattr(self, 'assertNumQueries'): - self.assertNumQueries(0, - lambda: reverse('tests.testapp.applicationcontent_urls/ac_module_root')) - - _empty_reverse_cache() - - self.assertNumQueries(1, - lambda: reverse('tests.testapp.applicationcontent_urls/ac_module_root')) - self.assertNumQueries(0, - lambda: reverse('tests.testapp.applicationcontent_urls/ac_module_root')) - - # This should not raise - self.assertEquals(self.client.get(page.get_absolute_url() + 'notexists/').status_code, 404) - - self.assertContains(self.client.get(page.get_absolute_url() + 'fragment/'), - 'some things') - - self.assertRedirects(self.client.get(page.get_absolute_url() + 'redirect/'), - page.get_absolute_url()) - - self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), - page.get_absolute_url()) - - response = self.client.get(page.get_absolute_url() + 'response/') - self.assertContains(response, 'Anything') - self.assertContains(response, '

Main content

') # Ensure response has been wrapped - - # Test standalone behavior - self.assertEqual( - self.client.get(page.get_absolute_url() + 'response/', - HTTP_X_REQUESTED_WITH='XMLHttpRequest').content, - self.client.get(page.get_absolute_url() + 'response_decorated/').content) - - # Test reversing of URLs (with overridden urls too) - page.applicationcontent_set.create( - region='main', - ordering=1, - urlconf_path='tests.testapp.blog_urls') - page1.applicationcontent_set.create( - region='main', - ordering=0, - urlconf_path='whatever') - - response = self.client.get(page.get_absolute_url() + 'alias_reverse_test/') - self.assertContains(response, 'home:/test-page/') - self.assertContains(response, 'args:/test-page/args_test/xy/zzy/') - self.assertContains(response, 'base:/test/') - - self.assertEqual(reverse('tests.testapp.blog_urls/blog_entry_list'), '/test-page/test-child-page/') - self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), - '/test-page/test-child-page/') - self.assertEqual(reverse('whatever/ac_module_root'), '/test-page/') - - page.applicationcontent_set.get(urlconf_path='tests.testapp.applicationcontent_urls').delete() - - self.assertEqual(reverse('tests.testapp.blog_urls/blog_entry_list'), '/test-page/test-child-page/') - self.assertEqual(reverse('whatever/ac_module_root'), '/test-page/') - - # Ensure ApplicationContent's admin_fields support works properly - self.assertContains(self.client.get('/admin/page/page/%d/' % page.id), - 'exclusive_subpages') - - def test_26_page_form_initial(self): - self.create_default_page_set() - - self.assertEqual(self.client.get('/admin/page/page/add/?translation_of=1&lang=de').status_code, 200) - self.assertEqual(self.client.get('/admin/page/page/add/?parent=1').status_code, 200) - self.assertEqual(self.client.get('/admin/page/page/add/?parent=2').status_code, 200) - - def test_27_cached_url_clash(self): - self.create_default_page_set() - - page1 = Page.objects.get(pk=1) - page2 = Page.objects.get(pk=2) - - page1.override_url = '/' - page1.active = True - page1.save() - - self.assertContains(self.create_pagecontent(page2, active=True, override_url='/'), - 'already taken by') - - def test_28_applicationcontent_reverse(self): - self.create_default_page_set() - page1 = Page.objects.get(pk=1) - page1.active = True - page1.save() - - page = Page.objects.get(pk=2) - page.active = True - page.template_key = 'theother' - page.save() - page.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='tests.testapp.applicationcontent_urls') - - from feincms.content.application.models import app_reverse, reverse - - # test app_reverse - self.assertEqual(app_reverse('ac_module_root', 'tests.testapp.applicationcontent_urls'), - page.get_absolute_url()) - - # test reverse replacement - should still work, but is deprecated - self.assertEqual(reverse('tests.testapp.applicationcontent_urls/ac_module_root'), - page.get_absolute_url()) - - # when specific applicationcontent exists more then once reverse should return url - # for the one that has tree_id same as current feincms page - self.create_page(title='Home DE', language='de', active=True) - page_de = Page.objects.get(title='Home DE') - self.create_page(title='Child 1 DE', language='de', parent=page_de.id, active=True) - page_de_1 = Page.objects.get(title='Child 1 DE') - page_de_1.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='tests.testapp.applicationcontent_urls') - _empty_reverse_cache() - - settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), 'templates'),) - self.client.get(page_de_1.get_absolute_url()) - self.assertEqual(app_reverse('ac_module_root', 'tests.testapp.applicationcontent_urls'), - page_de_1.get_absolute_url()) - - self.client.get(page1.get_absolute_url()) - self.assertEqual(app_reverse('ac_module_root', 'tests.testapp.applicationcontent_urls'), - page.get_absolute_url()) - - def test_29_medialibrary_admin(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - - mediafile = MediaFile.objects.create(file='somefile.jpg') - page.mediafilecontent_set.create( - mediafile=mediafile, - region='main', - position='block', - ordering=1) - - self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), 'somefile.jpg') - - import zipfile - zf = zipfile.ZipFile('test.zip', 'w') - for i in range(10): - zf.writestr('test%d.jpg' % i, 'test%d' % i) - zf.close() - - self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/mediafile-bulk-upload/', { - 'data': open('test.zip'), - }), '/admin/medialibrary/mediafile/') - - self.assertEqual(MediaFile.objects.count(), 11, "Upload of media files with ZIP does not work") - - self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/add/', { - 'file': open(os.path.join(os.path.dirname(os.path.dirname(__file__)), - 'docs', 'images', 'tree_editor.png')), - 'translations-TOTAL_FORMS': 0, - 'translations-INITIAL_FORMS': 0, - 'translations-MAX_NUM_FORMS': 10, - }), '/admin/medialibrary/mediafile/') - - self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), - '100x100.png" alt="" />') - - stats = list(MediaFile.objects.values_list('type', flat=True)) - self.assertEqual(stats.count('image'), 2) - self.assertEqual(stats.count('other'), 10) - - def test_30_context_processors(self): - self.create_default_page_set() - Page.objects.update(active=True, in_navigation=True) - - request = Empty() - request.GET = {} - request.META = {} - request.method = 'GET' - request.path = request.path_info = '/test-page/test-child-page/abcdef/' - request.get_full_path = lambda: '/test-page/test-child-page/abcdef/' - - ctx = add_page_if_missing(request) - self.assertEqual(ctx['feincms_page'], request._feincms_page) - - def test_31_sites_framework_associating_with_single_site(self): - self.login() - site_2 = Site.objects.create(name='site 2', domain='2.example.com') - self.create_page('site 1 homepage', override_url='/', active=True) - self.create_page('site 2 homepage', override_url='/', - site=site_2.id, active=True) - self.assertEqual(Page.objects.count(), 2) - self.assertEqual(Page.objects.active().count(), 1) - - def test_32_applicationcontent_inheritance20(self): - self.create_default_page_set() - - page1 = Page.objects.get(pk=1) - page1.active = True - page1.save() - - page = Page.objects.get(pk=2) - page.active = True - page.template_key = 'theother' - page.save() - - # Should not be published because the page has no application contents and should - # therefore not catch anything below it. - self.is_published(page1.get_absolute_url() + 'anything/', False) - - page.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='tests.testapp.applicationcontent_urls') - page.rawcontent_set.create( - region='main', ordering=1, text='some_main_region_text') - page.rawcontent_set.create( - region='sidebar', ordering=0, text='some_sidebar_region_text') - - self.assertContains(self.client.get(page.get_absolute_url()), - 'module_root') - - response = self.client.get(page.get_absolute_url() + 'inheritance20/') - self.assertContains(response, 'a content 42') - self.assertContains(response, 'b content') - self.assertNotContains(response, 'some_main_region_text') - self.assertContains(response, 'some_sidebar_region_text') - self.assertNotContains(response, 'some content outside') - - def test_33_preview(self): - self.create_default_page_set() - page = Page.objects.get(pk=1) - page.template_key = 'theother' - page.save() - page.rawcontent_set.create( - region='main', - ordering=0, - text='Example content') - - self.assertEquals(self.client.get(page.get_absolute_url()).status_code, 404) - self.assertContains(self.client.get('%s_preview/%s/' % (page.get_absolute_url(), page.pk)), - 'Example content') - - def test_34_access(self): - self.create_default_page_set() - - page = Page.objects.get(pk=1) - page.override_url = '/something/' - page.save() - - Page.objects.update(active=True) - - self.create_page(title='redirect page', override_url='/', redirect_to=page.get_absolute_url(), active=True) - - # / -> redirect to /something/ - r = self.client.get('/') - self.assertRedirects(r, page.get_absolute_url()) - # /something/ should work - r = self.client.get(page.override_url) - self.assertEquals(r.status_code, 200) - # /foo not existant -> 404 - r = self.client.get('/foo/') - self.assertEquals(r.status_code, 404) - - def test_35_access_with_extra_path(self): - self.login() - self.create_page(title='redirect again', override_url='/', redirect_to='/somewhere/', active=True) - self.create_page(title='somewhere', active=True) - - r = self.client.get('/') - self.assertRedirects(r, '/somewhere/') - r = self.client.get('/dingdong/') - self.assertEquals(r.status_code, 404) - - old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH - feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True - - r = self.client.get('/') - self.assertRedirects(r, '/somewhere/') - r = self.client.get('/dingdong/') - self.assertEquals(r.status_code, 404) - - feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old - Entry.register_extensions('seo', 'translations', 'seo', 'ct_tracker') class BlogTestCase(TestCase): def setUp(self): From 57a76c4d01078c2acc232d382eedc377f2ceeb35 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 13 Mar 2012 13:21:38 +0100 Subject: [PATCH 0266/1590] Remove unused imports. --- tests/tests/tests.py | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/tests/tests/tests.py b/tests/tests/tests.py index 2d37987e7..7a1a4f586 100644 --- a/tests/tests/tests.py +++ b/tests/tests/tests.py @@ -2,39 +2,16 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from datetime import datetime, timedelta -import os -import re - -from django import forms, template -from django.conf import settings -from django.contrib.auth.models import User, AnonymousUser -from django.contrib.contenttypes.models import ContentType -from django.core import mail -from django.core.urlresolvers import reverse -from django.db import models -from django.contrib.sites.models import Site -from django.http import Http404, HttpResponseBadRequest -from django.template import TemplateDoesNotExist -from django.template.defaultfilters import slugify +from django.contrib.auth.models import User from django.test import TestCase -from feincms import settings as feincms_settings -from feincms.content.application.models import _empty_reverse_cache from feincms.content.contactform.models import ContactFormContent, ContactForm from feincms.content.file.models import FileContent -from feincms.content.image.models import ImageContent -from feincms.content.raw.models import RawContent -from feincms.content.richtext.models import RichTextContent -from feincms.context_processors import add_page_if_missing -from feincms.models import Region, Template, Base, ContentProxy +from feincms.models import Region, Template, Base from feincms.module.blog.models import Entry -from feincms.module.medialibrary.models import Category, MediaFile from feincms.module.page import processors from feincms.module.page.models import Page -from feincms.templatetags import feincms_tags -from feincms.translations import short_language_code from feincms.utils import collect_dict_values, get_object # ------------------------------------------------------------------------ From 026b30baf51da17ad3fb41ed9876a0dd98b731f7 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 14 Mar 2012 15:43:41 +0100 Subject: [PATCH 0267/1590] Update included jquery to 1.7.1 --- feincms/static/feincms/jquery-1.7.1.min.js | 4 + feincms/static/feincms/jquery-1.7.js | 9300 ----------------- feincms/static/feincms/jquery-1.7.min.js | 4 - .../templates/admin/feincms/fe_editor.html | 2 +- .../admin/feincms/fe_editor_done.html | 2 +- feincms/templates/admin/feincms/fe_tools.html | 2 +- .../templates/admin/feincms/item_editor.html | 2 +- .../templates/admin/feincms/tree_editor.html | 2 +- 8 files changed, 9 insertions(+), 9309 deletions(-) create mode 100644 feincms/static/feincms/jquery-1.7.1.min.js delete mode 100644 feincms/static/feincms/jquery-1.7.js delete mode 100644 feincms/static/feincms/jquery-1.7.min.js diff --git a/feincms/static/feincms/jquery-1.7.1.min.js b/feincms/static/feincms/jquery-1.7.1.min.js new file mode 100644 index 000000000..198b3ff07 --- /dev/null +++ b/feincms/static/feincms/jquery-1.7.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-1.7.js b/feincms/static/feincms/jquery-1.7.js deleted file mode 100644 index eda55db35..000000000 --- a/feincms/static/feincms/jquery-1.7.js +++ /dev/null @@ -1,9300 +0,0 @@ -/*! - * jQuery JavaScript Library v1.7 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Nov 3 16:18:21 2011 -0400 - */ -(function( window, undefined ) { - -// Use the correct document accordingly with window argument (sandbox) -var document = window.document, - navigator = window.navigator, - location = window.location; -var jQuery = (function() { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - trimLeft = /^\s+/, - trimRight = /\s+$/, - - // Check for digits - rdigit = /\d/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, - rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - - // Useragent RegExp - rwebkit = /(webkit)[ \/]([\w.]+)/, - ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, - rmsie = /(msie) ([\w.]+)/, - rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, - - // Matches dashed string for camelizing - rdashAlpha = /-([a-z]|[0-9])/ig, - rmsPrefix = /^-ms-/, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // The deferred used on DOM ready - readyList, - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - trim = String.prototype.trim, - indexOf = Array.prototype.indexOf, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // The body element only exists once, optimize finding it - if ( selector === "body" && !context && document.body ) { - this.context = document; - this[0] = document.body; - this.selector = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = quickExpr.exec( selector ); - } - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context ? context.ownerDocument || context : document ); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; - } - - return jQuery.merge( this, selector ); - - // HANDLE: $("#id") - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.7", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return slice.call( this, 0 ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = this.constructor(); - - if ( jQuery.isArray( elems ) ) { - push.apply( ret, elems ); - - } else { - jQuery.merge( ret, elems ); - } - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Attach the listeners - jQuery.bindReady(); - - // Add the callback - readyList.add( fn ); - - return this; - }, - - eq: function( i ) { - return i === -1 ? - this.slice( i ) : - this.slice( i, +i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - // Either a released hold or an DOMready/load event and not yet ready - if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.fireWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger( "ready" ).unbind( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyList ) { - return; - } - - readyList = jQuery.Callbacks( "once memory" ); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - return setTimeout( jQuery.ready, 1 ); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - // A crude way of determining if an object is a window - isWindow: function( obj ) { - return obj && typeof obj === "object" && "setInterval" in obj; - }, - - isNumeric: function( obj ) { - return obj != null && rdigit.test( obj ) && !isNaN( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw msg; - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction( object ); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { - break; - } - } - } - } - - return object; - }, - - // Use native String.trim function wherever possible - trim: trim ? - function( text ) { - return text == null ? - "" : - trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // The extra typeof function check is to prevent crashes - // in Safari 2 (See: #3039) - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type( array ); - - if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( elem, array, i ) { - var len; - - if ( array ) { - if ( indexOf ) { - return indexOf.call( array, elem, i ); - } - - len = array.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in array && array[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var i = first.length, - j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var ret = [], retVal; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - if ( typeof context === "string" ) { - var tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - var args = slice.call( arguments, 2 ), - proxy = function() { - return fn.apply( context, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Mutifunctional method to get and set values to a collection - // The value/s can optionally be executed if it's a function - access: function( elems, key, value, exec, fn, pass ) { - var length = elems.length; - - // Setting many attributes - if ( typeof key === "object" ) { - for ( var k in key ) { - jQuery.access( elems, k, key[k], exec, fn, value ); - } - return elems; - } - - // Setting one attribute - if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = !pass && exec && jQuery.isFunction(value); - - for ( var i = 0; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - - return elems; - } - - // Getting an attribute - return length ? fn( elems[0], key ) : undefined; - }, - - now: function() { - return ( new Date() ).getTime(); - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = rwebkit.exec( ua ) || - ropera.exec( ua ) || - rmsie.exec( ua ) || - ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - sub: function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; - }, - - browser: {} -}); - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -// IE doesn't match non-breaking spaces with \s -if ( rnotwhite.test( "\xA0" ) ) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch(e) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -return jQuery; - -})(); - - -// String to Object flags format cache -var flagsCache = {}; - -// Convert String-formatted flags into Object-formatted ones and store in cache -function createFlags( flags ) { - var object = flagsCache[ flags ] = {}, - i, length; - flags = flags.split( /\s+/ ); - for ( i = 0, length = flags.length; i < length; i++ ) { - object[ flags[i] ] = true; - } - return object; -} - -/* - * Create a callback list using the following parameters: - * - * flags: an optional list of space-separated flags that will change how - * the callback list behaves - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible flags: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( flags ) { - - // Convert flags from String-formatted to Object-formatted - // (we check in cache first) - flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; - - var // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = [], - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Add one or several callbacks to the list - add = function( args ) { - var i, - length, - elem, - type, - actual; - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - // Inspect recursively - add( elem ); - } else if ( type === "function" ) { - // Add if not in unique mode and callback is not in - if ( !flags.unique || !self.has( elem ) ) { - list.push( elem ); - } - } - } - }, - // Fire callbacks - fire = function( context, args ) { - args = args || []; - memory = !flags.memory || [ context, args ]; - firing = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { - memory = true; // Mark as halted - break; - } - } - firing = false; - if ( list ) { - if ( !flags.once ) { - if ( stack && stack.length ) { - memory = stack.shift(); - self.fireWith( memory[ 0 ], memory[ 1 ] ); - } - } else if ( memory === true ) { - self.disable(); - } else { - list = []; - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - var length = list.length; - add( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away, unless previous - // firing was halted (stopOnFalse) - } else if ( memory && memory !== true ) { - firingStart = length; - fire( memory[ 0 ], memory[ 1 ] ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - var args = arguments, - argIndex = 0, - argLength = args.length; - for ( ; argIndex < argLength ; argIndex++ ) { - for ( var i = 0; i < list.length; i++ ) { - if ( args[ argIndex ] === list[ i ] ) { - // Handle firingIndex and firingLength - if ( firing ) { - if ( i <= firingLength ) { - firingLength--; - if ( i <= firingIndex ) { - firingIndex--; - } - } - } - // Remove the element - list.splice( i--, 1 ); - // If we have some unicity property then - // we only need to do this once - if ( flags.unique ) { - break; - } - } - } - } - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - if ( list ) { - var i = 0, - length = list.length; - for ( ; i < length; i++ ) { - if ( fn === list[ i ] ) { - return true; - } - } - } - return false; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory || memory === true ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( stack ) { - if ( firing ) { - if ( !flags.once ) { - stack.push( [ context, args ] ); - } - } else if ( !( flags.once && memory ) ) { - fire( context, args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!memory; - } - }; - - return self; -}; - - - - -var // Static reference to slice - sliceDeferred = [].slice; - -jQuery.extend({ - - Deferred: function( func ) { - var doneList = jQuery.Callbacks( "once memory" ), - failList = jQuery.Callbacks( "once memory" ), - progressList = jQuery.Callbacks( "memory" ), - state = "pending", - lists = { - resolve: doneList, - reject: failList, - notify: progressList - }, - promise = { - done: doneList.add, - fail: failList.add, - progress: progressList.add, - - state: function() { - return state; - }, - - // Deprecated - isResolved: doneList.fired, - isRejected: failList.fired, - - then: function( doneCallbacks, failCallbacks, progressCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); - return this; - }, - always: function() { - return deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); - }, - pipe: function( fnDone, fnFail, fnProgress ) { - return jQuery.Deferred(function( newDefer ) { - jQuery.each( { - done: [ fnDone, "resolve" ], - fail: [ fnFail, "reject" ], - progress: [ fnProgress, "notify" ] - }, function( handler, data ) { - var fn = data[ 0 ], - action = data[ 1 ], - returned; - if ( jQuery.isFunction( fn ) ) { - deferred[ handler ](function() { - returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - }); - } else { - deferred[ handler ]( newDefer[ action ] ); - } - }); - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - obj = promise; - } else { - for ( var key in promise ) { - obj[ key ] = promise[ key ]; - } - } - return obj; - } - }, - deferred = promise.promise({}), - key; - - for ( key in lists ) { - deferred[ key ] = lists[ key ].fire; - deferred[ key + "With" ] = lists[ key ].fireWith; - } - - // Handle state - deferred.done( function() { - state = "resolved"; - }, failList.disable, progressList.lock ).fail( function() { - state = "rejected"; - }, doneList.disable, progressList.lock ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( firstParam ) { - var args = sliceDeferred.call( arguments, 0 ), - i = 0, - length = args.length, - pValues = new Array( length ), - count = length, - pCount = length, - deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? - firstParam : - jQuery.Deferred(), - promise = deferred.promise(); - function resolveFunc( i ) { - return function( value ) { - args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - if ( !( --count ) ) { - deferred.resolveWith( deferred, args ); - } - }; - } - function progressFunc( i ) { - return function( value ) { - pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - deferred.notifyWith( promise, pValues ); - }; - } - if ( length > 1 ) { - for ( ; i < length; i++ ) { - if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { - args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( deferred, args ); - } - } else if ( deferred !== firstParam ) { - deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); - } - return promise; - } -}); - - - - -jQuery.support = (function() { - - var div = document.createElement( "div" ), - documentElement = document.documentElement, - all, - a, - select, - opt, - input, - marginDiv, - support, - fragment, - body, - testElementParent, - testElement, - testElementStyle, - tds, - events, - eventName, - i, - isSupported; - - // Preliminary tests - div.setAttribute("className", "t"); - div.innerHTML = "
a"; - - - all = div.getElementsByTagName( "*" ); - a = div.getElementsByTagName( "a" )[ 0 ]; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement( "select" ); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName( "input" )[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName( "tbody" ).length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName( "link" ).length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure unknown elements (like HTML5 elems) are handled appropriately - unknownElems: !!div.getElementsByTagName( "nav" ).length, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent( "onclick" ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute("type", "radio"); - support.radioValue = input.value === "t"; - - input.setAttribute("checked", "checked"); - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - div.innerHTML = ""; - - // Figure out if the W3C box model works as expected - div.style.width = div.style.paddingLeft = "1px"; - - // We don't want to do body-related feature tests on frameset - // documents, which lack a body. So we use - // document.getElementsByTagName("body")[0], which is undefined in - // frameset documents, while document.body isn’t. (7398) - body = document.getElementsByTagName("body")[ 0 ]; - // We use our own, invisible, body unless the body is already present - // in which case we use a div (#9239) - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - jQuery.extend( testElementStyle, { - position: "absolute", - left: "-999px", - top: "-999px" - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - support.boxModel = div.offsetWidth === 2; - - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); - } - - div.innerHTML = "
t
"; - tds = div.getElementsByTagName( "td" ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - div.innerHTML = ""; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - if ( document.defaultView && document.defaultView.getComputedStyle ) { - marginDiv = document.createElement( "div" ); - marginDiv.style.width = "0"; - marginDiv.style.marginRight = "0"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; - } - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for( i in { - submit: 1, - change: 1, - focusin: 1 - } ) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run fixed position tests at doc ready to avoid a crash - // related to the invisible body in IE8 - jQuery(function() { - var container, outer, inner, table, td, offsetSupport, - conMarginTop = 1, - ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;", - vb = "visibility:hidden;border:0;", - style = "style='" + ptlm + "border:5px solid #000;padding:0;'", - html = "
" + - "" + - "
"; - - // Reconstruct a container - body = document.getElementsByTagName("body")[0]; - if ( !body ) { - // Return for frameset docs that don't have a body - // These tests cannot be done - return; - } - - container = document.createElement("div"); - container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; - body.insertBefore( container, body.firstChild ); - - // Construct a test element - testElement = document.createElement("div"); - testElement.style.cssText = ptlm + vb; - - testElement.innerHTML = html; - container.appendChild( testElement ); - outer = testElement.firstChild; - inner = outer.firstChild; - td = outer.nextSibling.firstChild.firstChild; - - offsetSupport = { - doesNotAddBorder: ( inner.offsetTop !== 5 ), - doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) - }; - - inner.style.position = "fixed"; - inner.style.top = "20px"; - - // safari subtracts parent border width here which is 5px - offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); - inner.style.position = inner.style.top = ""; - - outer.style.overflow = "hidden"; - outer.style.position = "relative"; - - offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); - offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); - - body.removeChild( container ); - testElement = container = null; - - jQuery.extend( support, offsetSupport ); - }); - - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); - - // Null connected elements to avoid leaks in IE - testElement = fragment = select = opt = body = marginDiv = div = input = null; - - return support; -})(); - -// Keep track of boxModel -jQuery.boxModel = jQuery.support.boxModel; - - - - -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var privateCache, thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando, - isEvents = name === "events"; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ jQuery.expando ] = id = ++jQuery.uuid; - } else { - id = jQuery.expando; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - privateCache = thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Users should not attempt to inspect the internal events object using jQuery.data, - // it is undocumented and subject to change. But does anyone listen? No. - if ( isEvents && !thisCache[ name ] ) { - return privateCache.events; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - // Reference to internal data cache key - internalKey = jQuery.expando, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - - // See jQuery.data for more information - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support space separated names - if ( jQuery.isArray( name ) ) { - name = name; - } else if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split( " " ); - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject(cache[ id ]) ) { - return; - } - } - - // Browsers that fail expando deletion also refuse to delete expandos on - // the window, but it will allow it on all other JS objects; other browsers - // don't care - // Ensure that `cache` is not a window object #10080 - if ( jQuery.support.deleteExpando || !cache.setInterval ) { - delete cache[ id ]; - } else { - cache[ id ] = null; - } - - // We destroyed the cache and need to eliminate the expando on the node to avoid - // false lookups in the cache for entries that no longer exist - if ( isNode ) { - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( jQuery.support.deleteExpando ) { - delete elem[ jQuery.expando ]; - } else if ( elem.removeAttribute ) { - elem.removeAttribute( jQuery.expando ); - } else { - elem[ jQuery.expando ] = null; - } - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - if ( elem.nodeName ) { - var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; - - if ( match ) { - return !(match === true || elem.getAttribute("classid") !== match); - } - } - - return true; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, attr, name, - data = null; - - if ( typeof key === "undefined" ) { - if ( this.length ) { - data = jQuery.data( this[0] ); - - if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) { - attr = this[0].attributes; - for ( var i = 0, l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( this[0], name, data[ name ] ); - } - } - jQuery._data( this[0], "parsedAttrs", true ); - } - } - - return data; - - } else if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value === undefined ) { - data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - // Try to fetch any internally stored data first - if ( data === undefined && this.length ) { - data = jQuery.data( this[0], key ); - data = dataAttr( this[0], key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - - } else { - return this.each(function() { - var $this = jQuery( this ), - args = [ parts[0], value ]; - - $this.triggerHandler( "setData" + parts[1] + "!", args ); - jQuery.data( this, key, value ); - $this.triggerHandler( "changeData" + parts[1] + "!", args ); - }); - } - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - jQuery.isNumeric( data ) ? parseFloat( data ) : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - for ( var name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} - - - - -function handleQueueMarkDefer( elem, type, src ) { - var deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - defer = jQuery._data( elem, deferDataKey ); - if ( defer && - ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && - ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { - // Give room for hard-coded callbacks to fire first - // and eventually mark/queue something else on the element - setTimeout( function() { - if ( !jQuery._data( elem, queueDataKey ) && - !jQuery._data( elem, markDataKey ) ) { - jQuery.removeData( elem, deferDataKey, true ); - defer.fire(); - } - }, 0 ); - } -} - -jQuery.extend({ - - _mark: function( elem, type ) { - if ( elem ) { - type = ( type || "fx" ) + "mark"; - jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); - } - }, - - _unmark: function( force, elem, type ) { - if ( force !== true ) { - type = elem; - elem = force; - force = false; - } - if ( elem ) { - type = type || "fx"; - var key = type + "mark", - count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); - if ( count ) { - jQuery._data( elem, key, count ); - } else { - jQuery.removeData( elem, key, true ); - handleQueueMarkDefer( elem, type, "mark" ); - } - } - }, - - queue: function( elem, type, data ) { - var q; - if ( elem ) { - type = ( type || "fx" ) + "queue"; - q = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !q || jQuery.isArray(data) ) { - q = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - q.push( data ); - } - } - return q || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = {}; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - jQuery._data( elem, type + ".run", hooks ); - fn.call( elem, function() { - jQuery.dequeue( elem, type ); - }, hooks ); - } - - if ( !queue.length ) { - jQuery.removeData( elem, type + "queue " + type + ".run", true ); - handleQueueMarkDefer( elem, type, "queue" ); - } - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - } - - if ( data === undefined ) { - return jQuery.queue( this[0], type ); - } - return this.each(function() { - var queue = jQuery.queue( this, type, data ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, object ) { - if ( typeof type !== "string" ) { - object = type; - type = undefined; - } - type = type || "fx"; - var defer = jQuery.Deferred(), - elements = this, - i = elements.length, - count = 1, - deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - tmp; - function resolve() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - } - while( i-- ) { - if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || - ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || - jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && - jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { - count++; - tmp.add( resolve ); - } - } - resolve(); - return defer.promise(); - } -}); - - - - -var rclass = /[\n\t\r]/g, - rspace = /\s+/, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea)?$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute, - nodeHook, boolHook, fixSpecified; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.attr ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.prop ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classNames, i, l, elem, className, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - classNames = ( value || "" ).split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - className = (" " + elem.className + " ").replace( rclass, " " ); - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[ c ] + " ", " "); - } - elem.className = jQuery.trim( className ); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space seperated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return undefined; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var self = jQuery(this), val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return undefined; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( !("getAttribute" in elem) ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return undefined; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, l, - i = 0; - - if ( elem.nodeType === 1 ) { - attrNames = ( value || "" ).split( rspace ); - l = attrNames.length; - - for ( ; i < l; i++ ) { - name = attrNames[ i ].toLowerCase(); - propName = jQuery.propFix[ name ] || name; - - // See #9699 for explanation of this approach (setting first, then removal) - jQuery.attr( elem, name, "" ); - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( rboolean.test( name ) && propName in elem ) { - elem[ propName ] = false; - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return undefined; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) -jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? - ret.nodeValue : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.nodeValue = value + "" ); - } - }; - - // Apply the nodeHook to tabindex - jQuery.attrHooks.tabindex.set = nodeHook.set; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); - - - - -var rnamespaces = /\.(.*)$/, - rformElems = /^(?:textarea|input|select)$/i, - rperiod = /\./g, - rspaces = / /g, - rescape = /[^\w\s.|`]/g, - rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, - rhoverHack = /\bhover(\.\S+)?/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, - quickParse = function( selector ) { - var quick = rquickIs.exec( selector ); - if ( quick ) { - // 0 1 2 3 - // [ _, tag, id, class ] - quick[1] = ( quick[1] || "" ).toLowerCase(); - quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); - } - return quick; - }, - quickIs = function( elem, m ) { - return ( - (!m[1] || elem.nodeName.toLowerCase() === m[1]) && - (!m[2] || elem.id === m[2]) && - (!m[3] || m[3].test( elem.className )) - ); - }, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, quick, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = hoverHack(types).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Delegated event; pre-analyze selector so it's processed quickly on event dispatch - if ( selector ) { - handleObj.quick = quickParse( selector ); - if ( !handleObj.quick && jQuery.expr.match.POS.test( selector ) ) { - handleObj.isPositional = true; - } - } - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector ) { - - var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), - t, tns, type, namespaces, origCount, - j, events, special, handle, eventType, handleObj; - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = hoverHack( types || "" ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - namespaces = namespaces? "." + namespaces : ""; - for ( j in events ) { - jQuery.event.remove( elem, j + namespaces, handler, selector ); - } - return; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - - // Only need to loop for special events or selective removal - if ( handler || namespaces || selector || special.remove ) { - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( !handler || handler.guid === handleObj.guid ) { - if ( !namespaces || namespaces.test( handleObj.namespace ) ) { - if ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - } - } - } else { - // Removing all events - eventType.length = 0; - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - handle = elemData.handle; - if ( handle ) { - handle.elem = null; - } - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, [ "events", "handle" ], true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var type = event.type || event, - namespaces = [], - cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // triggerHandler() and global events don't bubble or run the default action - if ( onlyHandlers || !elem ) { - event.preventDefault(); - } - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - old = null; - for ( cur = elem.parentNode; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old && old === elem.ownerDocument ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length; i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) ) { - handle.apply( cur, data ); - } - - if ( event.isPropagationStopped() ) { - break; - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments, 0 ), - run_all = !event.exclusive && !event.namespace, - specialHandle = ( jQuery.event.special[ event.type ] || {} ).handle, - handlerQueue = [], - i, j, cur, ret, selMatch, matched, matches, handleObj, sel, hit, related; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Determine handlers that should run if there are delegated events - // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) { - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - selMatch = {}; - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - hit = selMatch[ sel ]; - - if ( handleObj.isPositional ) { - // Since .is() does not work for positionals; see http://jsfiddle.net/eJ4yd/3/ - hit = ( hit || (selMatch[ sel ] = jQuery( sel )) ).index( cur ) >= 0; - } else if ( hit === undefined ) { - hit = selMatch[ sel ] = ( handleObj.quick ? quickIs( cur, handleObj.quick ) : jQuery( cur ).is( sel ) ); - } - if ( hit ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( specialHandle || handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement wheelDelta".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) - if ( event.metaKey === undefined ) { - event.metaKey = event.ctrlKey; - } - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - focus: { - delegateType: "focusin", - noBubble: true - }, - blur: { - delegateType: "focusout", - noBubble: true - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - if ( elem.detachEvent ) { - elem.detachEvent( "on" + type, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = jQuery.event.special[ fix ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector, - oldType, ret; - - // For a real mouseover/out, always call the handler; for - // mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || handleObj.origType === event.type || (related !== target && !jQuery.contains( target, related )) ) { - oldType = event.type; - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = oldType; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !form._submit_attached ) { - jQuery.event.add( form, "submit._submit", function( event ) { - // Form was submitted, bubble the event up the tree - if ( this.parentNode ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - }); - form._submit_attached = true; - } - }); - // return undefined since we don't need an event listener - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed ) { - this._just_changed = false; - jQuery.event.simulate( "change", this, event, true ); - } - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - elem._change_attached = true; - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on.call( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - var handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( var type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.bind( name, data, fn ) : - this.trigger( name ); - }; - - if ( jQuery.attrFn ) { - jQuery.attrFn[ name ] = true; - } - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); - - - -/*! - * Sizzle CSS Selector Engine - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - expando = "sizcache" + (Math.random() + '').replace('.', ''), - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true, - rBackslash = /\\/g, - rReturn = /\r\n/g, - rNonWord = /\W/; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - - var origContext = context; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var m, set, checkSet, extra, ret, cur, pop, i, - prune = true, - contextXML = Sizzle.isXML( context ), - parts = [], - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - do { - chunker.exec( "" ); - m = chunker.exec( soFar ); - - if ( m ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - } while ( m ); - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context, seed ); - - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set, seed ); - } - } - - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - - ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? - Sizzle.filter( ret.expr, ret.set )[0] : - ret.set[0]; - } - - if ( context ) { - ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - - set = ret.expr ? - Sizzle.filter( ret.expr, ret.set ) : - ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray( set ); - - } else { - prune = false; - } - - while ( parts.length ) { - cur = parts.pop(); - pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - - } else if ( context && context.nodeType === 1 ) { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - - } else { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function( results ) { - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -Sizzle.matches = function( expr, set ) { - return Sizzle( expr, null, null, set ); -}; - -Sizzle.matchesSelector = function( node, expr ) { - return Sizzle( expr, null, null, [node] ).length > 0; -}; - -Sizzle.find = function( expr, context, isXML ) { - var set, i, len, match, type, left; - - if ( !expr ) { - return []; - } - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - left = match[1]; - match.splice( 1, 1 ); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace( rBackslash, "" ); - set = Expr.find[ type ]( match, context, isXML ); - - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = typeof context.getElementsByTagName !== "undefined" ? - context.getElementsByTagName( "*" ) : - []; - } - - return { set: set, expr: expr }; -}; - -Sizzle.filter = function( expr, set, inplace, not ) { - var match, anyFound, - type, found, item, filter, left, - i, pass, - old = expr, - result = [], - curLoop = set, - isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); - - while ( expr && set.length ) { - for ( type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - filter = Expr.filter[ type ]; - left = match[1]; - - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - pass = not ^ found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - - } else { - curLoop[i] = false; - } - - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw "Syntax error, unrecognized expression: " + msg; -}; - -/** - * Utility function for retreiving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var i, node, - nodeType = elem.nodeType, - ret = ""; - - if ( nodeType ) { - if ( nodeType === 1 ) { - // Use textContent || innerText for elements - if ( typeof elem.textContent === 'string' ) { - return elem.textContent; - } else if ( typeof elem.innerText === 'string' ) { - // Replace IE's carriage returns - return elem.innerText.replace( rReturn, '' ); - } else { - // Traverse it's children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - } else { - - // If no nodeType, this is expected to be an array - for ( i = 0; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - if ( node.nodeType !== 8 ) { - ret += getText( node ); - } - } - } - return ret; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - - match: { - ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - - leftMatch: {}, - - attrMap: { - "class": "className", - "for": "htmlFor" - }, - - attrHandle: { - href: function( elem ) { - return elem.getAttribute( "href" ); - }, - type: function( elem ) { - return elem.getAttribute( "type" ); - } - }, - - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !rNonWord.test( part ), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - - ">": function( checkSet, part ) { - var elem, - isPartStr = typeof part === "string", - i = 0, - l = checkSet.length; - - if ( isPartStr && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - - } else { - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - - "": function(checkSet, part, isXML){ - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); - }, - - "~": function( checkSet, part, isXML ) { - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); - } - }, - - find: { - ID: function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }, - - NAME: function( match, context ) { - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], - results = context.getElementsByName( match[1] ); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - - TAG: function( match, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( match[1] ); - } - } - }, - preFilter: { - CLASS: function( match, curLoop, inplace, result, not, isXML ) { - match = " " + match[1].replace( rBackslash, "" ) + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - - ID: function( match ) { - return match[1].replace( rBackslash, "" ); - }, - - TAG: function( match, curLoop ) { - return match[1].replace( rBackslash, "" ).toLowerCase(); - }, - - CHILD: function( match ) { - if ( match[1] === "nth" ) { - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - match[2] = match[2].replace(/^\+|\s*/g, ''); - - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - - ATTR: function( match, curLoop, inplace, result, not, isXML ) { - var name = match[1] = match[1].replace( rBackslash, "" ); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - // Handle if an un-quoted value was used - match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - - PSEUDO: function( match, curLoop, inplace, result, not ) { - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - - if ( !inplace ) { - result.push.apply( result, ret ); - } - - return false; - } - - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - - POS: function( match ) { - match.unshift( true ); - - return match; - } - }, - - filters: { - enabled: function( elem ) { - return elem.disabled === false && elem.type !== "hidden"; - }, - - disabled: function( elem ) { - return elem.disabled === true; - }, - - checked: function( elem ) { - return elem.checked === true; - }, - - selected: function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - parent: function( elem ) { - return !!elem.firstChild; - }, - - empty: function( elem ) { - return !elem.firstChild; - }, - - has: function( elem, i, match ) { - return !!Sizzle( match[3], elem ).length; - }, - - header: function( elem ) { - return (/h\d/i).test( elem.nodeName ); - }, - - text: function( elem ) { - var attr = elem.getAttribute( "type" ), type = elem.type; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); - }, - - radio: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; - }, - - checkbox: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; - }, - - file: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; - }, - - password: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; - }, - - submit: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "submit" === elem.type; - }, - - image: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; - }, - - reset: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "reset" === elem.type; - }, - - button: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && "button" === elem.type || name === "button"; - }, - - input: function( elem ) { - return (/input|select|textarea|button/i).test( elem.nodeName ); - }, - - focus: function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - setFilters: { - first: function( elem, i ) { - return i === 0; - }, - - last: function( elem, i, match, array ) { - return i === array.length - 1; - }, - - even: function( elem, i ) { - return i % 2 === 0; - }, - - odd: function( elem, i ) { - return i % 2 === 1; - }, - - lt: function( elem, i, match ) { - return i < match[3] - 0; - }, - - gt: function( elem, i, match ) { - return i > match[3] - 0; - }, - - nth: function( elem, i, match ) { - return match[3] - 0 === i; - }, - - eq: function( elem, i, match ) { - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function( elem, match, i, array ) { - var name = match[1], - filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; - - } else if ( name === "not" ) { - var not = match[3]; - - for ( var j = 0, l = not.length; j < l; j++ ) { - if ( not[j] === elem ) { - return false; - } - } - - return true; - - } else { - Sizzle.error( name ); - } - }, - - CHILD: function( elem, match ) { - var first, last, - doneName, parent, cache, - count, diff, - type = match[1], - node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - - case "nth": - first = match[2]; - last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - doneName = match[0]; - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { - count = 0; - - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - - parent[ expando ] = doneName; - } - - diff = elem.nodeIndex - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - - ID: function( elem, match ) { - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - - TAG: function( elem, match ) { - return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; - }, - - CLASS: function( elem, match ) { - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - - ATTR: function( elem, match ) { - var name = match[1], - result = Sizzle.attr ? - Sizzle.attr( elem, name ) : - Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - !type && Sizzle.attr ? - result != null : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - - POS: function( elem, match, i, array ) { - var name = match[2], - filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS, - fescape = function(all, num){ - return "\\" + (num - 0 + 1); - }; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); -} - -var makeArray = function( array, results ) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -// Also verifies that the returned array holds DOM nodes -// (which is not the case in the Blackberry browser) -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; - -// Provide a fallback method if it does not work -} catch( e ) { - makeArray = function( array, results ) { - var i = 0, - ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - - } else { - if ( typeof array.length === "number" ) { - for ( var l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - - } else { - for ( ; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder, siblingCheck; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - return a.compareDocumentPosition ? -1 : 1; - } - - return a.compareDocumentPosition(b) & 4 ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date()).getTime(), - root = document.documentElement; - - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( document.getElementById( id ) ) { - Expr.find.ID = function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - - return m ? - m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? - [m] : - undefined : - []; - } - }; - - Expr.filter.ID = function( elem, match ) { - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - - // release memory in IE - root = form = null; -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function( match, context ) { - var results = context.getElementsByTagName( match[1] ); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - - Expr.attrHandle.href = function( elem ) { - return elem.getAttribute( "href", 2 ); - }; - } - - // release memory in IE - div = null; -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, - div = document.createElement("div"), - id = "__sizzle__"; - - div.innerHTML = "

"; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function( query, context, extra, seed ) { - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && !Sizzle.isXML(context) ) { - // See if we find a selector to speed up - var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); - - if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { - // Speed-up: Sizzle("TAG") - if ( match[1] ) { - return makeArray( context.getElementsByTagName( query ), extra ); - - // Speed-up: Sizzle(".CLASS") - } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { - return makeArray( context.getElementsByClassName( match[2] ), extra ); - } - } - - if ( context.nodeType === 9 ) { - // Speed-up: Sizzle("body") - // The body element only exists once, optimize finding it - if ( query === "body" && context.body ) { - return makeArray( [ context.body ], extra ); - - // Speed-up: Sizzle("#ID") - } else if ( match && match[3] ) { - var elem = context.getElementById( match[3] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id === match[3] ) { - return makeArray( [ elem ], extra ); - } - - } else { - return makeArray( [], extra ); - } - } - - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(qsaError) {} - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var oldContext = context, - old = context.getAttribute( "id" ), - nid = old || id, - hasParent = context.parentNode, - relativeHierarchySelector = /^\s*[+~]/.test( query ); - - if ( !old ) { - context.setAttribute( "id", nid ); - } else { - nid = nid.replace( /'/g, "\\$&" ); - } - if ( relativeHierarchySelector && hasParent ) { - context = context.parentNode; - } - - try { - if ( !relativeHierarchySelector || hasParent ) { - return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); - } - - } catch(pseudoError) { - } finally { - if ( !old ) { - oldContext.removeAttribute( "id" ); - } - } - } - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - // release memory in IE - div = null; - })(); -} - -(function(){ - var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; - - if ( matches ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9 fails this) - var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } - - Sizzle.matchesSelector = function( node, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); - - if ( !Sizzle.isXML( node ) ) { - try { - if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - var ret = matches.call( node, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || !disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9, so check for that - node.document && node.document.nodeType !== 11 ) { - return ret; - } - } - } catch(e) {} - } - - return Sizzle(expr, null, null, [node]).length > 0; - }; - } -})(); - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
"; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function( match, context, isXML ) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - // release memory in IE - div = null; -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem[ expando ] = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem[ expando ] = doneName; - elem.sizset = i; - } - - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -if ( document.documentElement.contains ) { - Sizzle.contains = function( a, b ) { - return a !== b && (a.contains ? a.contains(b) : true); - }; - -} else if ( document.documentElement.compareDocumentPosition ) { - Sizzle.contains = function( a, b ) { - return !!(a.compareDocumentPosition(b) & 16); - }; - -} else { - Sizzle.contains = function() { - return false; - }; -} - -Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; - - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function( selector, context, seed ) { - var match, - tmpSet = [], - later = "", - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet, seed ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -Sizzle.selectors.attrMap = {}; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})(); - - -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - isSimple = /^.[^:#\[\.,]*$/, - slice = Array.prototype.slice, - POS = jQuery.expr.match.POS, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var self = this, - i, l; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - var ret = this.pushStack( "", "find", selector ), - length, n, r; - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - POS.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var ret = [], i, l, cur = this[0]; - - // Array (deprecated as of jQuery 1.7) - if ( jQuery.isArray( selectors ) ) { - var level = 1; - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( i = 0; i < selectors.length; i++ ) { - - if ( jQuery( cur ).is( selectors[ i ] ) ) { - ret.push({ selector: selectors[ i ], elem: cur, level: level }); - } - } - - cur = cur.parentNode; - level++; - } - - return ret; - } - - // String - var pos = POS.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( i = 0, l = this.length; i < l; i++ ) { - cur = this[i]; - - while ( cur ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - - } else { - cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { - break; - } - } - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( elem.parentNode.firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ), - // The variable 'args' was introduced in - // https://github.com/jquery/jquery/commit/52a0238 - // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. - // http://code.google.com/p/v8/issues/detail?id=1050 - args = slice.call(arguments); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, args.join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} - - - - -function createSafeFragment( document ) { - var list = nodeNames.split( " " ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr article aside audio canvas datalist details figcaption figure footer " + - "header hgroup mark meter nav output progress section summary time video", - rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, - rtagName = /<([\w:]+)/, - rtbody = /", "" ], - legend: [ 1, "
", "
" ], - thead: [ 1, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - col: [ 2, "", "
" ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and + + + {% endblock %} diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index e20bdd703..129f0c146 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -6,7 +6,7 @@ - + - From 78c0b6ba319c2b39520450ab0a2e922bfb063938 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 14 Jun 2012 10:44:13 +0200 Subject: [PATCH 0399/1590] FeinCMS v1.5.5 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index c89e454d7..614cc6e4d 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 5, 4) +VERSION = (1, 5, 5) __version__ = '.'.join(map(str, VERSION)) From 87d929498c25bff5356d1cbccd0a737e9c015d11 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn Date: Thu, 14 Jun 2012 21:29:27 +0100 Subject: [PATCH 0400/1590] Replace package dir only once. Was causing a packaging error with folder paths like 'feincms/static/feincms/img' becoming 'static/img' which doesn't exist. Correct path is 'static/feincms/img'. --- setuplib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuplib.py b/setuplib.py index a133afb0b..653029534 100644 --- a/setuplib.py +++ b/setuplib.py @@ -51,7 +51,7 @@ def find_packages(package_dir): package_data[cur_pack] = [] package_dir = "/".join(cur_pack.split(".")) + "/" for f in filenames: - package_data[cur_pack].append(os.path.join(dirpath.replace(package_dir, ""), f)) + package_data[cur_pack].append(os.path.join(dirpath.replace(package_dir, "", 1), f)) return packages, package_data From 5a387311c048aa64b781139b2de229dd2184be93 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 08:28:56 +0200 Subject: [PATCH 0401/1590] FeinCMS v1.6.1 Always the packaging. --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 45929273e..21e077e5e 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 6, 0) +VERSION = (1, 6, 1) __version__ = '.'.join(map(str, VERSION)) From 55d5286539a1f2c8a55e7201b92cf1e291e130a8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 10:27:54 +0200 Subject: [PATCH 0402/1590] Fix #304: Mention page.models and medialibrary.models split in release notes --- docs/deprecation.rst | 4 ++++ docs/releases/1.6.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index c36a1b52b..4ead17bd9 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -29,6 +29,10 @@ will be issued for at least two releases. * ``feincms.views.base`` has been moved to ``feincms.views.legacy``. Use ``feincms.views.cbv`` instead. * ``FEINCMS_FRONTEND_EDITING``'s default has been changed to ``False``. +* The code in :mod:`feincms.module.page.models` has been split up. The admin + classes are in :mod:`feincms.module.page.modeladmin`, the forms in + :mod:`feincms.module.page.forms` now. Analogous changes have been made + to :mod:`feincms.module.medialibrary.models`. 1.7 diff --git a/docs/releases/1.6.rst b/docs/releases/1.6.rst index 1be544506..7980982b4 100644 --- a/docs/releases/1.6.rst +++ b/docs/releases/1.6.rst @@ -183,6 +183,10 @@ Notable features and improvements * Media files are now removed from the disk too if a media file entry is removed from the database. +* The modules :mod:`feincms.module.page.models` and + :mod:`feincms.module.medialibrary.models` have been split up. Admin code has + been moved into ``modeladmin.py`` files, form code into ``forms.py``. + Bugfixes ======== From 9e1b208c8c407d3069263148b318dd9f35ce7bdb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 11:16:18 +0200 Subject: [PATCH 0403/1590] Rewrap feincms/models.py a bit Yes, I work on small screens too. --- feincms/models.py | 272 +++++++++++++++++++++++++++------------------- 1 file changed, 158 insertions(+), 114 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index ad401c057..5eb543253 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -46,7 +46,8 @@ def content_types(self): of (content type key, beautified content type name) tuples """ - return [(ct.__name__.lower(), ct._meta.verbose_name) for ct in self._content_types] + return [(ct.__name__.lower(), ct._meta.verbose_name) + for ct in self._content_types] class Template(object): @@ -81,8 +82,8 @@ def __unicode__(self): class ContentProxy(object): """ The ``ContentProxy`` is responsible for loading the content blocks for all - regions (including content blocks in inherited regions) and assembling media - definitions. + regions (including content blocks in inherited regions) and assembling + media definitions. The content inside a region can be fetched using attribute access with the region key. This is achieved through a custom ``__getattr__`` @@ -105,7 +106,8 @@ def _inherit_from(self): is good enough (tm) for pages. """ - return self.item.get_ancestors(ascending=True).values_list('pk', flat=True) + return self.item.get_ancestors(ascending=True).values_list( + 'pk', flat=True) def _fetch_content_type_counts(self): """ @@ -180,40 +182,49 @@ def _popuplate_content_type_caches(self, types): counts_by_type = {} for region, counts in self._fetch_content_type_counts().items(): for pk, ct_idx in counts: - counts_by_type.setdefault(self.item._feincms_content_types[ct_idx], []).append((region, pk)) + counts_by_type.setdefault( + self.item._feincms_content_types[ct_idx], + [], + ).append((region, pk)) # Resolve abstract to concrete content types - types = tuple(types) + content_types = (cls for cls in self.item._feincms_content_types + if issubclass(cls, tuple(types))) - for type in (type for type in self.item._feincms_content_types if issubclass(type, types)): - counts = counts_by_type.get(type) - if type not in self._cache['cts']: + for cls in content_types: + counts = counts_by_type.get(cls) + if cls not in self._cache['cts']: if counts: - self._cache['cts'][type] = list(type.get_queryset( - reduce(operator.or_, (Q(region=r[0], parent=r[1]) for r in counts)))) + self._cache['cts'][cls] = list(cls.get_queryset( + reduce(operator.or_, ( + Q(region=r[0], parent=r[1]) for r in counts)))) else: - self._cache['cts'][type] = [] + self._cache['cts'][cls] = [] def _fetch_regions(self): """ + Fetches all content types and group content types into regions """ if 'regions' not in self._cache: self._popuplate_content_type_caches(self.item._feincms_content_types) contents = {} - for type, content_list in self._cache['cts'].items(): + for cls, content_list in self._cache['cts'].items(): for instance in content_list: contents.setdefault(instance.region, []).append(instance) - self._cache['regions'] = dict((region, sorted(instances, key=lambda c: c.ordering))\ - for region, instances in contents.iteritems()) + self._cache['regions'] = dict(( + region, + sorted(instances, key=lambda c: c.ordering), + ) for region, instances in contents.iteritems()) + return self._cache['regions'] def all_of_type(self, type_or_tuple): """ - Return all content type instances belonging to the type or types passed. - If you want to filter for several types at the same time, type must be - a tuple. + Returns all content type instances belonging to the type or types + passed. If you want to filter for several types at the same time, type + must be a tuple. """ content_list = [] @@ -310,9 +321,10 @@ def register_extensions(cls, *extensions): fn = get_object('%s.%s.register' % (path, ext)) if fn: warnings.warn( - 'Using short names for extensions has been deprecated' - ' and will be removed in FeinCMS v1.8.' - ' Please provide the full python path to the extension' + 'Using short names for extensions has been' + ' deprecated and will be removed in' + ' FeinCMS v1.8. Please provide the full' + ' python path to the extension' ' %s instead (%s.%s).' % (ext, path, ext), DeprecationWarning, stacklevel=2) @@ -321,8 +333,9 @@ def register_extensions(cls, *extensions): pass if not fn: - raise ImproperlyConfigured, '%s is not a valid extension for %s' % ( - ext, cls.__name__) + raise ImproperlyConfigured( + '%s is not a valid extension for %s' % ( + ext, cls.__name__)) # Not a string, maybe a callable? elif hasattr(ext, '__call__'): @@ -338,9 +351,9 @@ def register_extensions(cls, *extensions): def create_base_model(inherit_from=models.Model): """ - This method can be used to create a FeinCMS base model inheriting from your - own custom subclass (f.e. extend ``MPTTModel``). The default is to extend - :class:`django.db.models.Model`. + This method can be used to create a FeinCMS base model inheriting from + your own custom subclass (f.e. extend ``MPTTModel``). The default is to + extend :class:`django.db.models.Model`. """ class Base(inherit_from, ExtensionsMixin): @@ -358,7 +371,8 @@ class Meta: def register_regions(cls, *regions): """ Register a list of regions. Only use this if you do not want to use - multiple templates with this model (read: not use ``register_templates``):: + multiple templates with this model (read: not use + ``register_templates``):: BlogEntry.register_regions( ('main', _('Main content area')), @@ -379,8 +393,8 @@ def register_regions(cls, *regions): @classmethod def register_templates(cls, *templates): """ - Register templates and add a ``template_key`` field to the model for - saving the selected template:: + Register templates and add a ``template_key`` field to the model + for saving the selected template:: Page.register_templates({ 'key': 'base', @@ -417,7 +431,8 @@ def register_templates(cls, *templates): try: field = cls._meta.get_field_by_name('template_key')[0] except (FieldDoesNotExist, IndexError): - cls.add_to_class('template_key', models.CharField(_('template'), max_length=255, choices=())) + cls.add_to_class('template_key', + models.CharField(_('template'), max_length=255, choices=())) field = cls._meta.get_field_by_name('template_key')[0] def _template(self): @@ -433,8 +448,10 @@ def _template(self): cls.template = property(_template) - cls.TEMPLATE_CHOICES = field._choices = [(template.key, template.title) - for template in cls._feincms_templates.values()] + cls.TEMPLATE_CHOICES = field._choices = [( + template.key, + template.title, + ) for template in cls._feincms_templates.values()] field.default = field.choices[0][0] # Build a set of all regions used anywhere @@ -448,8 +465,8 @@ def _template(self): @property def content(self): """ - Instantiate and return a ``ContentProxy``. You can use your own custom - ``ContentProxy`` by assigning a different class to the + Instantiate and return a ``ContentProxy``. You can use your own + custom ``ContentProxy`` by assigning a different class to the ``content_proxy_class`` member variable. """ @@ -461,18 +478,20 @@ def content(self): @classmethod def _create_content_base(cls): """ - This is purely an internal method. Here, we create a base class for the - concrete content types, which are built in ``create_content_type``. + This is purely an internal method. Here, we create a base class for + the concrete content types, which are built in + ``create_content_type``. - The three fields added to build a concrete content type class/model are - ``parent``, ``region`` and ``ordering``. + The three fields added to build a concrete content type class/model + are ``parent``, ``region`` and ``ordering``. """ - # We need a template, because of the possibility of restricting content types - # to a subset of all available regions. Each region object carries a list of - # all allowed content types around. Content types created before a region is - # initialized would not be available in the respective region; we avoid this - # problem by raising an ImproperlyConfigured exception early. + # We need a template, because of the possibility of restricting + # content types to a subset of all available regions. Each region + # object carries a list of all allowed content types around. + # Content types created before a region is initialized would not be + # available in the respective region; we avoid this problem by + # raising an ImproperlyConfigured exception early. cls._needs_templates() class Meta: @@ -481,15 +500,16 @@ class Meta: ordering = ['ordering'] def __unicode__(self): - return u'%s on %s, ordering %s' % (self.region, self.parent, self.ordering) + return u'%s on %s, ordering %s' % ( + self.region, self.parent, self.ordering) def render(self, **kwargs): """ - Default render implementation, tries to call a method named after the - region key before giving up. + Default render implementation, tries to call a method named + after the region key before giving up. - You'll probably override the render method itself most of the time - instead of adding region-specific render methods. + You'll probably override the render method itself most of the + time instead of adding region-specific render methods. """ render_fn = getattr(self, 'render_%s' % self.region, None) @@ -517,9 +537,10 @@ def fe_render(self, **kwargs): def fe_identifier(self): """ - Returns an identifier which is understood by the frontend editing - javascript code. (It is used to find the URL which should be used - to load the form for every given block of content.) + Returns an identifier which is understood by the frontend + editing javascript code. (It is used to find the URL which + should be used to load the form for every given block of + content.) """ return u'%s-%s-%s-%s-%s' % ( @@ -562,76 +583,87 @@ def get_queryset(cls, filter_args): # before or after rendering the content: # # def process(self, request, **kwargs): - # May return a response early to short-circuit the request-response cycle + # May return a response early to short-circuit the + # request-response cycle # # def finalize(self, request, response) - # May modify the response or replace it entirely by returning a new one + # May modify the response or replace it entirely by returning + # a new one # cls._feincms_content_types_with_process = [] cls._feincms_content_types_with_finalize = [] - # list of item editor context processors, will be extended by content types + # list of item editor context processors, will be extended by + # content types if hasattr(cls, 'feincms_item_editor_context_processors'): - cls.feincms_item_editor_context_processors = list(cls.feincms_item_editor_context_processors) + cls.feincms_item_editor_context_processors = list( + cls.feincms_item_editor_context_processors) else: cls.feincms_item_editor_context_processors = [] - # list of templates which should be included in the item editor, will be extended - # by content types + # list of templates which should be included in the item editor, + # will be extended by content types if hasattr(cls, 'feincms_item_editor_includes'): - cls.feincms_item_editor_includes = dict(cls.feincms_item_editor_includes) + cls.feincms_item_editor_includes = dict( + cls.feincms_item_editor_includes) else: cls.feincms_item_editor_includes = {} @classmethod - def create_content_type(cls, model, regions=None, class_name=None, **kwargs): + def create_content_type(cls, model, regions=None, class_name=None, + **kwargs): """ This is the method you'll use to create concrete content types. - If the CMS base class is ``page.models.Page``, its database table will be - ``page_page``. A concrete content type which is created from ``ImageContent`` - will use ``page_page_imagecontent`` as its table. + If the CMS base class is ``page.models.Page``, its database table + will be ``page_page``. A concrete content type which is created + from ``ImageContent`` will use ``page_page_imagecontent`` as its + table. - If you want a content type only available in a subset of regions, you can - pass a list/tuple of region keys as ``regions``. The content type will only - appear in the corresponding tabs in the item editor. + If you want a content type only available in a subset of regions, + you can pass a list/tuple of region keys as ``regions``. The + content type will only appear in the corresponding tabs in the item + editor. If you use two content types with the same name in the same module, name clashes will happen and the content type created first will shadow all subsequent content types. You can work around it by specifying the content type class name using the ``class_name`` - argument. Please note that this will have an effect on the entries in - ``django_content_type``, on ``related_name`` and on the table name - used and should therefore not be changed after running ``syncdb`` for - the first time. + argument. Please note that this will have an effect on the entries + in ``django_content_type``, on ``related_name`` and on the table + name used and should therefore not be changed after running + ``syncdb`` for the first time. Name clashes will also happen if a content type has defined a - relationship and you try to register that content type to more than one - Base model (in different modules). Django will raise an error when it - tries to create the backward relationship. The solution to that problem - is, as shown above, to specify the content type class name with the - ``class_name`` argument. + relationship and you try to register that content type to more than + one Base model (in different modules). Django will raise an error + when it tries to create the backward relationship. The solution to + that problem is, as shown above, to specify the content type class + name with the ``class_name`` argument. If you register a content type to more than one Base class, it is recommended to always specify a ``class_name`` when registering it a second time. - You can pass additional keyword arguments to this factory function. These - keyword arguments will be passed on to the concrete content type, provided - that it has a ``initialize_type`` classmethod. This is used f.e. in - ``MediaFileContent`` to pass a set of possible media positions (f.e. left, - right, centered) through to the content type. + You can pass additional keyword arguments to this factory function. + These keyword arguments will be passed on to the concrete content + type, provided that it has a ``initialize_type`` classmethod. This + is used f.e. in ``MediaFileContent`` to pass a set of possible + media positions (f.e. left, right, centered) through to the content + type. """ if not class_name: class_name = model.__name__ - # prevent double registration and registration of two different content types - # with the same class name because of related_name clashes + # prevent double registration and registration of two different + # content types with the same class name because of related_name + # clashes try: getattr(cls, '%s_set' % class_name.lower()) warnings.warn( - 'Cannot create content type using %s.%s for %s.%s, because %s_set is already taken.' % ( + 'Cannot create content type using %s.%s for %s.%s,' + ' because %s_set is already taken.' % ( model.__module__, class_name, cls.__module__, cls.__name__, class_name.lower()), @@ -641,19 +673,22 @@ def create_content_type(cls, model, regions=None, class_name=None, **kwargs): # everything ok pass - # Next name clash test. Happens when the same content type is created - # for two Base subclasses living in the same Django application - # (github issues #73 and #150) + # Next name clash test. Happens when the same content type is + # created for two Base subclasses living in the same Django + # application (github issues #73 and #150) other_model = get_model(cls._meta.app_label, class_name) if other_model: warnings.warn( - 'It seems that the content type %s exists twice in %s. Use the class_name argument to create_content_type to avoid this error.' % ( + 'It seems that the content type %s exists twice in %s.' + ' Use the class_name argument to create_content_type to' + ' avoid this error.' % ( model.__name__, cls._meta.app_label), RuntimeWarning) if not model._meta.abstract: - raise ImproperlyConfigured, 'Cannot create content type from non-abstract model (yet).' + raise ImproperlyConfigured('Cannot create content type from' + ' non-abstract model (yet).') if not hasattr(cls, '_feincms_content_model'): cls._create_content_base() @@ -666,13 +701,14 @@ class Meta(feincms_content_base.Meta): verbose_name_plural = model._meta.verbose_name_plural attrs = { - '__module__': cls.__module__, # put the concrete content type into the - # same module as the CMS base type; this is - # necessary because 1. Django needs to know - # the module where a model lives and 2. a - # content type may be used by several CMS - # base models at the same time (f.e. in - # the blog and the page module). + # put the concrete content type into the + # same module as the CMS base type; this is + # necessary because 1. Django needs to know + # the module where a model lives and 2. a + # content type may be used by several CMS + # base models at the same time (f.e. in + # the blog and the page module). + '__module__': cls.__module__, 'Meta': Meta, } @@ -689,16 +725,18 @@ class Meta(feincms_content_base.Meta): # content types can be limited to a subset of regions if not regions: - regions = set([region.key for region in cls._feincms_all_regions]) + regions = set([region.key for region + in cls._feincms_all_regions]) for region in cls._feincms_all_regions: if region.key in regions: region._content_types.append(new_type) - # Add a list of CMS base types for which a concrete content type has - # been created to the abstract content type. This is needed f.e. for the - # update_rsscontent management command, which needs to find all concrete - # RSSContent types, so that the RSS feeds can be fetched + # Add a list of CMS base types for which a concrete content type + # has been created to the abstract content type. This is needed + # f.e. for the update_rsscontent management command, which needs to + # find all concrete RSSContent types, so that the RSS feeds can be + # fetched if not hasattr(model, '_feincms_content_models'): model._feincms_content_models = [] @@ -707,7 +745,8 @@ class Meta(feincms_content_base.Meta): # Add a backlink from content-type to content holder class new_type._feincms_content_class = cls - # Handle optgroup argument for grouping content types in the item editor + # Handle optgroup argument for grouping content types in the item + # editor optgroup = kwargs.pop('optgroup', None) if optgroup: new_type.optgroup = optgroup @@ -727,7 +766,8 @@ class Meta(feincms_content_base.Meta): # collect item editor includes from the content type if hasattr(model, 'feincms_item_editor_includes'): for key, includes in model.feincms_item_editor_includes.items(): - cls.feincms_item_editor_includes.setdefault(key, set()).update(includes) + cls.feincms_item_editor_includes.setdefault( + key, set()).update(includes) return new_type @@ -746,7 +786,8 @@ def content_type_for(cls, model): concrete_type = Page.content_type_for(VideoContent) """ - if not hasattr(cls, '_feincms_content_types') or not cls._feincms_content_types: + if (not hasattr(cls, '_feincms_content_types') + or not cls._feincms_content_types): return None for type in cls._feincms_content_types: @@ -758,26 +799,28 @@ def content_type_for(cls, model): def _needs_templates(cls): ensure_completely_loaded() - # helper which can be used to ensure that either register_regions or - # register_templates has been executed before proceeding + # helper which can be used to ensure that either register_regions + # or register_templates has been executed before proceeding if not hasattr(cls, 'template'): - raise ImproperlyConfigured, 'You need to register at least one template or one region on %s.' % ( - cls.__name__, - ) + raise ImproperlyConfigured('You need to register at least one' + ' template or one region on %s.' % cls.__name__) @classmethod def _needs_content_types(cls): ensure_completely_loaded() - # Check whether any content types have been created for this base class - if not hasattr(cls, '_feincms_content_types') or not cls._feincms_content_types: - raise ImproperlyConfigured, 'You need to create at least one content type for the %s model.' % (cls.__name__) + # Check whether any content types have been created for this base + # class + if (not hasattr(cls, '_feincms_content_types') + or not cls._feincms_content_types): + raise ImproperlyConfigured('You need to create at least one' + ' content type for the %s model.' % cls.__name__) def copy_content_from(self, obj): """ - Copy all content blocks over to another CMS base object. (Must be of the - same type, but this is not enforced. It will crash if you try to copy content - from another CMS base type.) + Copy all content blocks over to another CMS base object. (Must be + of the same type, but this is not enforced. It will crash if you + try to copy content from another CMS base type.) """ for cls in self._feincms_content_types: @@ -790,7 +833,8 @@ def replace_content_with(self, obj): """ Replace the content of the current object with content of another. - Deletes all content blocks and calls ``copy_content_from`` afterwards. + Deletes all content blocks and calls ``copy_content_from`` + afterwards. """ for cls in self._feincms_content_types: From 25a9f2a2e67ffbd90426a1fa6d35555772092ae3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 11:46:17 +0200 Subject: [PATCH 0404/1590] Always check the frontend editing state on cookies --- feincms/models.py | 4 +++- feincms/templatetags/feincms_tags.py | 2 +- feincms/tests/page_tests.py | 2 +- feincms/views/legacy/views.py | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 5eb543253..498b8a972 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -527,7 +527,9 @@ def fe_render(self, **kwargs): if 'request' in kwargs: request = kwargs['request'] - if request.session and request.session.get('frontend_editing'): + if (hasattr(request, 'COOKIES') + and request.COOKIES.get('frontend_editing')): + return render_to_string('admin/feincms/fe_box.html', { 'content': self.render(**kwargs), 'identifier': self.fe_identifier(), diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index cb72dfaa2..b4bb76d18 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -56,7 +56,7 @@ def feincms_frontend_editing(cms_obj, request): {% feincms_frontend_editing feincms_page request %} """ - if hasattr(request, 'session') and request.session.get('frontend_editing'): + if hasattr(request, 'COOKIES') and request.COOKIES.get('frontend_editing'): context = template.RequestContext(request, { "feincms_page": cms_obj, }) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index daa729ff4..c975c4aa9 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -589,7 +589,7 @@ def test_15_frontend_editing(self): self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') request = Empty() - request.session = {'frontend_editing': True} + request.COOKIES = {'frontend_editing': True} self.assertTrue('class="fe_box"' in\ page.content.main[0].fe_render(request=request)) diff --git a/feincms/views/legacy/views.py b/feincms/views/legacy/views.py index d9a700262..a6f8b2aa3 100644 --- a/feincms/views/legacy/views.py +++ b/feincms/views/legacy/views.py @@ -92,7 +92,8 @@ def finalize(self, request, response, page): page.finalize_response(request, response) # Add never cache headers in case frontend editing is active - if hasattr(request, "session") and request.session.get('frontend_editing', False): + if (hasattr(request, "COOKIES") + and request.COOKIES.get('frontend_editing')): add_never_cache_headers(response) return response From 5ad30e05a6452efef7fed7d8401769bae302b24e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 11:47:23 +0200 Subject: [PATCH 0405/1590] PEP8-clean feincms/models.py --- feincms/models.py | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 498b8a972..f2aaf9a60 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -150,11 +150,14 @@ def _fetch_content_type_counts(self): return self._cache['counts'] def _fetch_content_type_count_helper(self, pk, regions=None): - tmpl = ['SELECT %d AS ct_idx, region, COUNT(id) FROM %s WHERE parent_id=%s'] + tmpl = [ + 'SELECT %d AS ct_idx, region, COUNT(id) FROM %s WHERE parent_id=%s' + ] args = [] if regions: - tmpl.append('AND region IN (' + ','.join(['%%s'] * len(regions)) + ')') + tmpl.append( + 'AND region IN (' + ','.join(['%%s'] * len(regions)) + ')') args.extend(regions * len(self.item._feincms_content_types)) tmpl.append('GROUP BY region') @@ -207,7 +210,8 @@ def _fetch_regions(self): """ if 'regions' not in self._cache: - self._popuplate_content_type_caches(self.item._feincms_content_types) + self._popuplate_content_type_caches( + self.item._feincms_content_types) contents = {} for cls, content_list in self._cache['cts'].items(): for instance in content_list: @@ -432,7 +436,8 @@ def register_templates(cls, *templates): field = cls._meta.get_field_by_name('template_key')[0] except (FieldDoesNotExist, IndexError): cls.add_to_class('template_key', - models.CharField(_('template'), max_length=255, choices=())) + models.CharField(_('template'), max_length=255, choices=()) + ) field = cls._meta.get_field_by_name('template_key')[0] def _template(self): @@ -557,12 +562,13 @@ def get_queryset(cls, filter_args): return cls.objects.select_related().filter(filter_args) attrs = { - '__module__': cls.__module__, # The basic content type is put into - # the same module as the CMS base type. - # If an app_label is not given, Django - # needs to know where a model comes - # from, therefore we ensure that the - # module is always known. + # The basic content type is put into + # the same module as the CMS base type. + # If an app_label is not given, Django + # needs to know where a model comes + # from, therefore we ensure that the + # module is always known. + '__module__': cls.__module__, '__unicode__': __unicode__, 'render': render, 'fe_render': fe_render, @@ -767,16 +773,17 @@ class Meta(feincms_content_base.Meta): # collect item editor includes from the content type if hasattr(model, 'feincms_item_editor_includes'): - for key, includes in model.feincms_item_editor_includes.items(): + for key, incls in model.feincms_item_editor_includes.items(): cls.feincms_item_editor_includes.setdefault( - key, set()).update(includes) + key, set()).update(incls) return new_type @property def _django_content_type(self): - if getattr(self.__class__, '_cached_django_content_type', None) is None: - self.__class__._cached_django_content_type = ContentType.objects.get_for_model(self) + if not getattr(self, '_cached_django_content_type', None): + self.__class__._cached_django_content_type = ( + ContentType.objects.get_for_model(self)) return self.__class__._cached_django_content_type @classmethod @@ -827,7 +834,8 @@ def copy_content_from(self, obj): for cls in self._feincms_content_types: for content in cls.objects.filter(parent=obj): - new = copy_model_instance(content, exclude=('id', 'parent')) + new = copy_model_instance(content, + exclude=('id', 'parent')) new.parent = self new.save() @@ -851,10 +859,9 @@ def register_with_reversion(cls): raise EnvironmentError("django-reversion is not installed") follow = [] - for content_type_model in cls._feincms_content_types: - related_manager = "%s_set" % content_type_model.__name__.lower() - follow.append(related_manager) - reversion.register(content_type_model) + for content_type in cls._feincms_content_types: + follow.append('%s_set' % content_type.__name__.lower()) + reversion.register(content_type) reversion.register(cls, follow=follow) return Base From 65c057a5fdef9703829745f4387b07553e8f31cd Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 14:58:24 +0200 Subject: [PATCH 0406/1590] Fix #261: 255 chars in URL paths should be enough for everyone (tm) ... MySQL sometimes cannot create indexes on longer fields --- feincms/module/page/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 4be2a8a29..969905113 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -143,11 +143,11 @@ class Page(create_base_model(MPTTModel)): parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, null=True, related_name='children') parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py in_navigation = models.BooleanField(_('in navigation'), default=True) - override_url = models.CharField(_('override URL'), max_length=300, blank=True, + override_url = models.CharField(_('override URL'), max_length=255, blank=True, help_text=_('Override the target URL. Be sure to include slashes at the beginning and at the end if it is a local URL. This affects both the navigation and subpages\' URLs.')) - redirect_to = models.CharField(_('redirect to'), max_length=300, blank=True, + redirect_to = models.CharField(_('redirect to'), max_length=255, blank=True, help_text=_('Target URL for automatic redirects.')) - _cached_url = models.CharField(_('Cached URL'), max_length=300, blank=True, + _cached_url = models.CharField(_('Cached URL'), max_length=255, blank=True, editable=False, default='', db_index=True) request_processors = SortedDict() From 3f59f3ec176b07e27a85426e39835bd0cee2d7f8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 15:15:39 +0200 Subject: [PATCH 0407/1590] Fix #220: Move items into existing regions when switching templates --- feincms/static/feincms/item_editor.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 37bccb280..fd77349f4 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -441,11 +441,11 @@ if(!Array.indexOf) { jConfirm(msg, CHANGE_TEMPLATE_MESSAGES[0], function(ret) { if(ret) { for(var i=0; i Date: Fri, 15 Jun 2012 16:15:41 +0200 Subject: [PATCH 0408/1590] Add a lazy version of app_reverse Thanks to Marc Tamlyn for the suggestion. --- docs/releases/1.7.rst | 4 ++++ feincms/content/application/models.py | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index 7921115f6..da84439c3 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -34,6 +34,10 @@ FeinCMS 1.7 requires Django 1.4. Notable features and improvements ================================= +* A lazy version of :py:func:`~feincms.content.application.models.app_reverse` + is now available, + :py:func:`~feincms.content.application.models.app_reverse_lazy`. + Bugfixes diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 3d9659138..b84b5452c 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -10,7 +10,7 @@ from django.core.urlresolvers import Resolver404, resolve, reverse, NoReverseMatch from django.db import models from django.http import HttpResponse -from django.utils.functional import curry as partial, wraps +from django.utils.functional import curry as partial, lazy, wraps from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ @@ -180,6 +180,10 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, raise NoReverseMatch("Unable to find ApplicationContent for '%s'" % urlconf) +#: Lazy version of ``app_reverse`` +app_reverse_lazy = lazy(app_reverse, str) + + def permalink(func): """ Decorator that calls app_reverse() From b6a340282383ad33b3149a457d5aeb494bf92ae7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 16:16:46 +0200 Subject: [PATCH 0409/1590] Add some comments to feincms_nav --- feincms/module/page/templatetags/feincms_page_tags.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 95deba9e4..d87d60534 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -57,10 +57,12 @@ def feincms_nav(context, feincms_page, level=1, depth=1): parent = feincms_page.get_ancestors()[level - 2] if parent: - # Special case for navigation extensions if getattr(parent, 'navigation_extension', None): + # Special case for navigation extensions return parent.extended_navigation(depth=depth, request=context.get('request')) + + # Apply descendant filter queryset &= parent.get_descendants() if depth > 1: From 63bf5c09f6a252c662502e1d3dd3c0ff04119ead Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 15 Jun 2012 16:17:02 +0200 Subject: [PATCH 0410/1590] Improve table content initialization --- feincms/templates/admin/content/table/init.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/feincms/templates/admin/content/table/init.html b/feincms/templates/admin/content/table/init.html index 27978f63a..149769a75 100644 --- a/feincms/templates/admin/content/table/init.html +++ b/feincms/templates/admin/content/table/init.html @@ -120,8 +120,14 @@ table.siblings('textarea').val($.toJSON(data)); } + var tablecontent_added = {}; + contentblock_init_handlers.push(function(){ - $('.order-machine textarea[name*=tablecontent]:visible').each(function(){ + $('.order-machine textarea[name*=tablecontent]').each(function(){ + if (tablecontent_added[this.id]) + return; + tablecontent_added[this.id] = true; + var textarea = $(this); var data = $.secureEvalJSON(textarea.val() || '[[""]]'); From 4ae15a54ca8a79da1b32f4f146ecdf28a334d69b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 16 Jun 2012 13:56:25 +0200 Subject: [PATCH 0411/1590] Replace default_create_content_type invocations --- example/models.py | 4 +++- tests/testapp/models.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/example/models.py b/example/models.py index feb9ba341..f932dd879 100644 --- a/example/models.py +++ b/example/models.py @@ -25,7 +25,9 @@ ), }) Page.create_content_type(RawContent) -MediaFileContent.default_create_content_type(Page) +Page.create_content_type(MediaFileContent, TYPE_CHOICES=( + ('default', 'Default position'), + )) Page.create_content_type(ImageContent, POSITION_CHOICES=( ('default', 'Default position'), )) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 73a8aa777..502bf7355 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -25,7 +25,9 @@ ), }) Page.create_content_type(RawContent) -MediaFileContent.default_create_content_type(Page) +Page.create_content_type(MediaFileContent, TYPE_CHOICES=( + ('default', 'Default position'), + )) Page.create_content_type(ImageContent, POSITION_CHOICES=( ('default', 'Default position'), )) From cbc09c8a95c5b7ea3ee9c4b1371e90d27439792e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 16 Jun 2012 13:58:45 +0200 Subject: [PATCH 0412/1590] Update tests for MediaFileContent v2 --- feincms/tests/page_tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index c975c4aa9..505f445d5 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -317,7 +317,7 @@ def create_pagecontent(self, page, **kwargs): 'mediafilecontent_set-MAX_NUM_FORMS': 10, 'mediafilecontent_set-0-parent': 1, - 'mediafilecontent_set-0-position': 'block', + 'mediafilecontent_set-0-type': 'default', 'imagecontent_set-TOTAL_FORMS': 1, 'imagecontent_set-INITIAL_FORMS': 0, @@ -388,7 +388,7 @@ def test_10_mediafile_and_imagecontent(self): page.mediafilecontent_set.create( mediafile=mediafile, region='main', - position='block', + type='default', ordering=1) self.assertEqual(unicode(mediafile), 'somefile.jpg') @@ -1183,7 +1183,7 @@ def test_29_medialibrary_admin(self): page.mediafilecontent_set.create( mediafile=mediafile, region='main', - position='block', + type='default', ordering=1) self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), 'somefile.jpg') From 54ad1fe73ab137d876e585994c266d9e58fbcefb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 16 Jun 2012 14:01:53 +0200 Subject: [PATCH 0413/1590] Enforce the presence of TYPE_CHOICES when initializing a MediaFileContent --- feincms/content/medialibrary/models.py | 5 +++++ feincms/tests/cms_tests.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 577cf7d04..c22c7d13f 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -3,6 +3,7 @@ # ------------------------------------------------------------------------ from django.contrib import admin +from django.core.exceptions import ImproperlyConfigured from django.db import models from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ @@ -50,6 +51,10 @@ class Meta: @classmethod def initialize_type(cls, TYPE_CHOICES=None): + if TYPE_CHOICES is None: + raise ImproperlyConfigured('You have to set TYPE_CHOICES when' + ' creating a %s' % cls.__name__) + cls.add_to_class('type', models.CharField(_('type'), max_length=20, choices=TYPE_CHOICES, default=TYPE_CHOICES[0][0])) diff --git a/feincms/tests/cms_tests.py b/feincms/tests/cms_tests.py index 39b5514ca..4f13a42fe 100644 --- a/feincms/tests/cms_tests.py +++ b/feincms/tests/cms_tests.py @@ -66,7 +66,7 @@ def test_04_mediafilecontent_creation(self): from feincms.content.medialibrary.models import MediaFileContent - # no POSITION_CHOICES, should raise + # no TYPE_CHOICES, should raise self.assertRaises(ImproperlyConfigured, lambda: ExampleCMSBase.create_content_type(MediaFileContent)) From ec0f5baf448d872e463f8ed6eca263f03148ad31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= Date: Sat, 16 Jun 2012 17:51:47 +0200 Subject: [PATCH 0414/1590] update docs: installation and page for FeinCMS 1.6 --- docs/installation.rst | 32 ++++++++++++++++----------- docs/page.rst | 51 ++++++++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 39ffe76b0..21919704c 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -10,24 +10,26 @@ Installation This document describes the steps needed to get FeinCMS up and running. FeinCMS is based on Django, so you need a working Django_ installation -first. The minimum support version of Django_ is the 1.3 line of releases. +first. The minimum support version of Django_ is the 1.4 line of releases. -You can download a stable release of FeinCMS using ``easy_install``:: +You can download a stable release of FeinCMS using ``pip``:: - $ sudo easy_install feincms + $ pip install feincms -Please note that the package installable with ``easy_install`` only -contains the files needed to run FeinCMS. It does not include documentation, -tests or the example project which comes with the development version, +Pip will install feincms and its dependencies. It will however not install +documentation, tests or the example project which comes with the development version, which you can download using the Git_ version control system:: $ git clone git://github.com/feincms/feincms.git -In addition, you will need a django-mptt_ installation. +Feincms, some content types or cleaning modules are dependent on the following apps, which are installed when using pip: +lxml_, feedparser_, PIL_, django-mptt_ and BeautifulSoup_. -Finally, some content types or extensions require recent versions of -lxml_, django-tagging_, feedparser_ and the python imaging library PIL_ -(PIL_ is actually a dependency of Django_'s ImageField). +However, django-tagging_ is not installed because the blog module that uses it is merely a proof of +concept. If you are looking to implement a blog, check out elephantblog_. + +You will also need a Javascript WYSIWYG editor of your choice (Not included). +TinyMCE_ works out of the box and is recommended. .. _Django: http://www.djangoproject.com/ @@ -38,20 +40,24 @@ lxml_, django-tagging_, feedparser_ and the python imaging library PIL_ .. _lxml: http://codespeak.net/lxml/ .. _feedparser: http://www.feedparser.org/ .. _PIL: http://www.pythonware.com/products/pil/ +.. _BeautifulSoup: http://pypi.python.org/pypi/BeautifulSoup/3.2.1 +.. _elephantblog: http://github.com/feincms/feincms-elephantblog +.. _TinyMCE: http://www.tinymce.com/ +.. _CKEditor: http://ckeditor.com/ Configuration ============= There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS``, -most commonly you'll want to add ``feincms``, ``feincms.module.page`` and +most commonly you'll want to add ``feincms``, ``mptt``, ``feincms.module.page`` and ``feincms.module.medialibrary``. The customized administration interface needs some media and javascript libraries which you have to make available to the browser. FeinCMS uses Django's ``django.contrib.staticfiles`` application for this purpose, the media files will be picked up automatically by the ``collectstatic`` management command. -If your website is multi-language you have to define ``LANGUAGES_`` in the settings. +If your website is multi-language you have to define ``LANGUAGES`` in the settings_. Please note that the ``feincms`` module will not create or need any database tables, but you need to put it into ``INSTALLED_APPS`` because otherwise the @@ -63,4 +69,4 @@ pages and this is the most advanced module of FeinCMS too. Please proceed to :ref:`page` to find out how you can get the page module up and running. -.. _LANGUAGES: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#how-django-discovers-language-preference \ No newline at end of file +.. _settings: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#how-django-discovers-language-preference \ No newline at end of file diff --git a/docs/page.rst b/docs/page.rst index 2ad9404a3..7b77947c5 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -28,7 +28,7 @@ several extensions. You need to create some content models too. No models are created by default, because there is no possibility to unregister models. A sane default might -be to create :class:`~feincms.content.image.models.ImageContent` and +be to create :class:`~feincms.content.medialibrary.models.MediaFileContent` and :class:`~feincms.content.richtext.models.RichTextContent` models; you can do this by adding the following lines somewhere into your project, for example in a ``models.py`` file that will be processed anyway:: @@ -37,7 +37,7 @@ by adding the following lines somewhere into your project, for example in a from feincms.module.page.models import Page from feincms.content.richtext.models import RichTextContent - from feincms.content.medialibrary.v2 import MediaFileContent + from feincms.content.medialibrary.models import MediaFileContent Page.register_extensions('datepublisher', 'translations') # Example set of extensions @@ -64,8 +64,7 @@ content type dropdown will contain content types in the same order as they were registered. Please note that you should put these statements into a ``models.py`` file -which is executed at Django startup time, i.e. into a ``models.py`` file -contained in ``INSTALLED_APPS``. +of an app contained in ``INSTALLED_APPS``. That file is executed at Django startup time. Setting up the admin interface @@ -75,11 +74,11 @@ The customized admin interface code is contained inside the :class:`ModelAdmin` subclass, so you do not need to do anything special here. If you use the :class:`~feincms.content.richtext.models.RichTextContent`, you -need to download `TinyMCE `_ and configure FeinCMS' +need to download `TinyMCE `_ and configure FeinCMS' richtext support:: FEINCMS_RICHTEXT_INIT_CONTEXT = { - 'TINYMCE_JS_URL': '/your_custom_path/tiny_mce.js', + 'TINYMCE_JS_URL': STATIC_URL + 'your_custom_path/tiny_mce.js', } @@ -162,20 +161,35 @@ be activated as follows:: The following extensions are available currently: -* :mod:`~feincms.module.page.extension.changedate` --- Creation and modification dates +* :mod:`~feincms.module.extensions.changedate` --- Creation and modification dates Adds automatically maintained creation and modification date fields to the page. -* :mod:`~feincms.module.page.extension.datepublisher` --- Date-based publishing +* :mod:`~feincms.module.extensions.ct_tracker` --- Content type cache + + Helps reduce database queries if you have three or more content types. + + +* :mod:`~feincms.module.extensions.datepublisher` --- Date-based publishing Adds publication date and end date fields to the page, thereby enabling the administrator to define a date range where a page will be available to website visitors. -* :mod:`~feincms.module.page.extension.navigation` --- Navigation extensions +* :mod:`~feincms.module.page.extensions.excerpt` --- Page summary + + Add a brief excerpt summarizing the content of this page. + + +* :mod:`~feincms.module.extensions.featured` --- Simple featured flag for a page + + Lets administrators set a featured flag that lets you treat that page special. + + +* :mod:`~feincms.module.page.extensions.navigation` --- Navigation extensions Adds navigation extensions to the page model. You can define subclasses of ``NavigationExtension``, which provide submenus to the navigation generation @@ -183,19 +197,29 @@ The following extensions are available currently: this extension. -* :mod:`~feincms.module.page.extension.seo` --- Search engine optimization +* :mod:`~feincms.module.page.extensions.relatedpages` --- Links related content + + Add a many-to-many relationship field to relate this page to other pages. + + +* :mod:`~feincms.module.extensions.seo` --- Search engine optimization Adds fields to the page relevant for search engine optimization (SEO), currently only meta keywords and description. -* :mod:`~feincms.module.page.extension.symlinks` --- Symlinked content extension +* :mod:`~feincms.module.page.extensions.sites` --- Limit pages to sites + + Allows to limit a page to a certain site and not display it on other sites. + + +* :mod:`~feincms.module.page.extensions.symlinks` --- Symlinked content extension Sometimes you want to reuse all content from a page in another place. This extension lets you do that. -* :mod:`~feincms.module.page.extension.titles` --- Additional titles +* :mod:`~feincms.module.page.extensions.titles` --- Additional titles Adds additional title fields to the page model. You may not only define a single title for the page to be used in the navigation, the tag and @@ -204,7 +228,7 @@ The following extensions are available currently: content area. -* :mod:`~feincms.module.page.extension.translations` --- Page translations +* :mod:`~feincms.module.extensions.translations` --- Page translations Adds a language field and a recursive translations many to many field to the page, so that you can define the language the page is in and assign @@ -220,6 +244,7 @@ The following extensions are available currently: behavior in non-FeinCMS managed views (such as third party apps not integrated using :class:`feincms.content.application.models.ApplicationContent` or Django's own administration tool). + You need to have defined ``settings.LANGUAGES`` as well. .. note:: From d14bff6af0df9e942edf789cd788d8ed2274b6cc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 09:49:33 +0200 Subject: [PATCH 0415/1590] Decouple models and views some more Move the processor and content type handling from Page and Handler into reusable classes. This commit is essentially a big move of code and should not have caused any change of behavior. Unfortunately it did: It moves the execution of request processors where it belongs (in the view), which means that they aren't run in Page.setup_request anymore, which in turn causes the require_path_active_request_processor to NOT run inside the page manager methods, which means that now inactive pages may be returned from the following methods: - Page.objects.page_for_path - Page.objects.best_match_for_path - Page.for_request The next commit tries rectifying that. Refs #241. --- feincms/contrib/preview/views.py | 15 +-- feincms/module/mixins.py | 205 +++++++++++++++++++++++++++++++ feincms/module/page/models.py | 84 +------------ feincms/views/cbv/views.py | 92 ++------------ 4 files changed, 223 insertions(+), 173 deletions(-) create mode 100644 feincms/module/mixins.py diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 088425399..967faf9f6 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -18,25 +18,20 @@ def handler(self, request, path, page_id): if not request.user.is_staff: raise Http404 - self.page = get_object_or_404(Page, pk=page_id) + page = get_object_or_404(Page, pk=page_id) # Throw out request processor which will cause the page to-be-previewed # to be seen as inactive (which is the case, of course) - self.page.request_processors = self.page.request_processors.copy() - self.page.register_request_processor( + page.request_processors = page.request_processors.copy() + page.register_request_processor( lambda page, response: None, # Do nothing key='path_active') # Remove _preview/42/ from URL, the rest of the handler code should not # know that anything about previewing. Handler.prepare will still raise # a 404 if the extra_path isn't consumed by any content type - request.path = self.page.get_absolute_url() + request.path = page.get_absolute_url() - response = self.prepare() - if response: - return response - - response = self.render_to_response(self.get_context_data()) - response = self.finalize(response) + response = self.handle_object(page) response['Cache-Control'] = 'no-cache, must-revalidate, no-store, private' return response diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py new file mode 100644 index 000000000..342b9b167 --- /dev/null +++ b/feincms/module/mixins.py @@ -0,0 +1,205 @@ +import re + +from django.db import models +from django.http import Http404 +from django.template import Template +from django.utils.cache import add_never_cache_headers +from django.utils.datastructures import SortedDict +from django.views.generic import TemplateView + +from feincms import settings + + +class ContentMixin(object): + """ + Mixin for ``feincms.models.Base`` subclasses which need need some degree of + additional control over the request-response cycle. + """ + + #: Collection of request processors + request_processors = SortedDict() + + #: Collection of response processors + response_processors = SortedDict() + + def setup_request(self, request): + if not hasattr(request, '_feincms_extra_context'): + request._feincms_extra_context = {} + + @classmethod + def register_request_processor(cls, fn, key=None): + """ + Registers the passed callable as request processor. A request processor + always receives two arguments, the current object and the request. + """ + cls.request_processors[fn if key is None else key] = fn + + @classmethod + def register_response_processor(cls, fn, key=None): + """ + Registers the passed callable as response processor. A response + processor always receives three arguments, the current object, the + request and the response. + """ + cls.response_processors[fn if key is None else key] = fn + + +class ContentView(TemplateView): + #: The name of the object for the template rendering context + context_object_name = 'feincms_object' + + def get(self, request, *args, **kwargs): + return self.handler(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + return self.handler(request, *args, **kwargs) + + def handler(self, request, *args, **kwargs): + self.page = Page.objects.for_request(request, + raise404=True, best_match=True, setup=False) + + def handle_object(self, object): + if not hasattr(self.request, '_feincms_extra_context'): + self.request._feincms_extra_context = {} + + self.object = object + + r = self.run_request_processors() + if r: + return r + + r = self.process_content_types() + if r: + return r + + response = self.render_to_response(self.get_context_data()) + + r = self.finalize_content_types(response) + if r: + return r + + r = self.run_response_processors(response) + if r: + return r + + return response + + def get_template_names(self): + # According to the documentation this method is supposed to return + # a list. However, we can also return a Template instance... + if isinstance(self.template_name, (Template, list, tuple)): + return self.template_name + + if self.template_name: + return [self.template_name] + + # Hopefully someone run register_templates on the object class + # beforehand, otherwise we'll crash... + return [self.object.template.path] + + def get_context_data(self, **kwargs): + context = self.request._feincms_extra_context + context[self.context_object_name] = self.object + return context + + @property + def __name__(self): + """ + Dummy property to make this handler behave like a normal function. + This property is used by django-debug-toolbar + """ + return self.__class__.__name__ + + def run_request_processors(self): + """ + Before rendering an object, run all registered request processors. A + request processor may peruse and modify the page or the request. It can + also return a ``HttpResponse`` for shortcutting the rendering and + returning that response immediately to the client. + """ + + self.request._feincms_extra_context.update({ + # XXX This variable name isn't accurate anymore. + # We _are_ in a subpage, but it isn't necessarily + # an appcontent subpage. + 'in_appcontent_subpage': False, + 'extra_path': '/', + }) + + url = self.object.get_absolute_url() + if self.request.path != url: + # extra_path must not end with a slash + self.request._feincms_extra_context.update({ + 'in_appcontent_subpage': True, + 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', + self.request.path), + }) + + for fn in reversed(self.object.request_processors.values()): + r = fn(self.object, self.request) + if r: + return r + + def run_response_processors(self, response): + """ + After rendering an object to a response, the registered response + processors are called to modify the response, eg. for setting cache or + expiration headers, keeping statistics, etc. + """ + for fn in self.object.response_processors.values(): + r = fn(self.object, self.request, response) + if r: + return r + + def process_content_types(self): + """ + Run the ``process`` method of all content types sporting one + """ + # store eventual Http404 exceptions for re-raising, + # if no content type wants to handle the current self.request + http404 = None + # did any content type successfully end processing? + successful = False + + for content in self.object.content.all_of_type(tuple( + self.object._feincms_content_types_with_process)): + + try: + r = content.process(self.request, view=self) + if r in (True, False): + successful = r + elif r: + return r + except Http404, e: + http404 = e + + if not successful: + if http404: + # re-raise stored Http404 exception + raise http404 + + if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ + self.request._feincms_extra_context['extra_path'] != '/': + raise Http404 + + def finalize_content_types(self, response): + """ + Runs finalize() on content types having such a method, adds headers and + returns the final response. + """ + + for content in self.object.content.all_of_type(tuple( + self.object._feincms_content_types_with_finalize)): + + r = content.finalize(self.request, response) + if r: + return r + + # Add never cache headers in case frontend editing is active + if (hasattr(self.request, "COOKIES") + and self.request.COOKIES.get('frontend_editing', False)): + + if hasattr(response, 'add_post_render_callback'): + response.add_post_render_callback(add_never_cache_headers) + else: + add_never_cache_headers(response) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 969905113..7bc0ffc9c 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -9,7 +9,6 @@ from django.db import models from django.db.models import Q, signals from django.http import Http404 -from django.utils.datastructures import SortedDict from django.utils.translation import ugettext_lazy as _ from django.db.transaction import commit_on_success @@ -18,6 +17,7 @@ from feincms import settings from feincms.management.checker import check_database_schema from feincms.models import create_base_model +from feincms.module.mixins import ContentMixin from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin @@ -134,7 +134,7 @@ def for_request(self, request, raise404=False, best_match=False, setup=True): PageManager.add_to_active_filters(Q(active=True)) # ------------------------------------------------------------------------ -class Page(create_base_model(MPTTModel)): +class Page(create_base_model(MPTTModel), ContentMixin): active = models.BooleanField(_('active'), default=True) # structure and navigation @@ -150,8 +150,6 @@ class Page(create_base_model(MPTTModel)): _cached_url = models.CharField(_('Cached URL'), max_length=255, blank=True, editable=False, default='', db_index=True) - request_processors = SortedDict() - response_processors = SortedDict() cache_key_components = [ lambda p: django_settings.SITE_ID, lambda p: p._django_content_type.id, lambda p: p.id ] @@ -296,84 +294,12 @@ def last_modified(self, request): """ return None - def setup_request(self, request): - """ - Before rendering a page, run all registered request processors. A request - processor may peruse and modify the page or the request. It can also return - a HttpResponse for shortcutting the page rendering and returning that response - immediately to the client. - - ``setup_request`` stores responses returned by request processors and returns - those on every subsequent call to ``setup_request``. This means that - ``setup_request`` can be called repeatedly during the same request-response - cycle without harm - request processors are executed exactly once. - """ - - if hasattr(self, '_setup_request_result'): - return self._setup_request_result - else: - # Marker -- setup_request has been successfully run before - self._setup_request_result = None - - if not hasattr(request, '_feincms_extra_context'): - request._feincms_extra_context = {} - - request._feincms_extra_context.update({ - 'in_appcontent_subpage': False, # XXX This variable name isn't accurate anymore. - # We _are_ in a subpage, but it isn't necessarily - # an appcontent subpage. - 'extra_path': '/', - }) - - url = self.get_absolute_url() - if request.path != url: - # extra_path must not end with a slash - request._feincms_extra_context.update({ - 'in_appcontent_subpage': True, - 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', - request.path), - }) - - for fn in reversed(self.request_processors.values()): - r = fn(self, request) - if r: - self._setup_request_result = r - break - - return self._setup_request_result - - def finalize_response(self, request, response): - """ - After rendering a page to a response, the registered response processors are - called to modify the response, eg. for setting cache or expiration headers, - keeping statistics, etc. - """ - for fn in self.response_processors.values(): - fn(self, request, response) - def get_redirect_to_target(self, request): """ This might be overriden/extended by extension modules. """ return self.redirect_to - @classmethod - def register_request_processor(cls, fn, key=None): - """ - Registers the passed callable as request processor. A request processor - always receives two arguments, the current page object and the request. - """ - cls.request_processors[fn if key is None else key] = fn - - @classmethod - def register_response_processor(cls, fn, key=None): - """ - Registers the passed callable as response processor. A response processor - always receives three arguments, the current page object, the request - and the response. - """ - cls.response_processors[fn if key is None else key] = fn - @classmethod def register_extension(cls, register_fn): register_fn(cls, PageAdmin) @@ -385,13 +311,15 @@ def path_to_cache_key(path): # ------------------------------------------------------------------------ # Our default request processors -Page.register_request_processor(processors.require_path_active_request_processor, +Page.register_request_processor( + processors.require_path_active_request_processor, key='path_active') Page.register_request_processor(processors.redirect_request_processor, key='redirect') if settings.FEINCMS_FRONTEND_EDITING: - Page.register_request_processor(processors.frontendediting_request_processor, + Page.register_request_processor( + processors.frontendediting_request_processor, key='frontend_editing') signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index b3e1cbc74..0c6e51306 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -1,17 +1,17 @@ from django.http import Http404 -from django.template import Template -from django.utils.cache import add_never_cache_headers -from django.views.generic import TemplateView from feincms import settings +from feincms.module.mixins import ContentView from feincms.module.page.models import Page -class HandlerBase(TemplateView): +class HandlerBase(ContentView): """ Class-based handler for FeinCMS page content """ + context_object_name = 'feincms_page' + def get(self, request, *args, **kwargs): return self.handler(request, *args, **kwargs) @@ -19,89 +19,11 @@ def post(self, request, *args, **kwargs): return self.handler(request, *args, **kwargs) def handler(self, request, *args, **kwargs): - self.page = Page.objects.for_request(request, raise404=True, best_match=True, setup=False) - response = self.prepare() - if response: - return response - - response = self.render_to_response(self.get_context_data()) - return self.finalize(response) - - def get_template_names(self): - # According to the documentation this method is supposed to return - # a list. However, we can also return a Template instance... - if isinstance(self.template_name, (Template, list, tuple)): - return self.template_name - - return [self.template_name or self.page.template.path] - - def get_context_data(self, **kwargs): - context = self.request._feincms_extra_context - context['feincms_page'] = self.page - return context - - def prepare(self): - """ - Prepare / pre-process content types. If this method returns anything, - it is treated as a ``HttpResponse`` and handed back to the visitor. - """ - - response = self.page.setup_request(self.request) - if response: - return response - - http404 = None # store eventual Http404 exceptions for re-raising, - # if no content type wants to handle the current self.request - successful = False # did any content type successfully end processing? - - for content in self.page.content.all_of_type(tuple(self.page._feincms_content_types_with_process)): - try: - r = content.process(self.request, view=self) - if r in (True, False): - successful = r - elif r: - return r - except Http404, e: - http404 = e - - if not successful: - if http404: - # re-raise stored Http404 exception - raise http404 - - if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ - self.request._feincms_extra_context['extra_path'] != '/': - raise Http404 - - def finalize(self, response): - """ - Runs finalize() on content types having such a method, adds headers and - returns the final response. - """ - - for content in self.page.content.all_of_type(tuple(self.page._feincms_content_types_with_finalize)): - r = content.finalize(self.request, response) - if r: - return r - - self.page.finalize_response(self.request, response) - - # Add never cache headers in case frontend editing is active - if hasattr(self.request, "COOKIES") and self.request.COOKIES.get('frontend_editing', False): - if hasattr(response, 'add_post_render_callback'): - response.add_post_render_callback(add_never_cache_headers) - else: - add_never_cache_headers(response) + page = Page.objects.for_request(request, + raise404=True, best_match=True, setup=False) - return response + return self.handle_object(page) - @property - def __name__(self): - """ - Dummy property to make this handler behave like a normal function. - This property is used by django-debug-toolbar - """ - return self.__class__.__name__ # ------------------------------------------------------------------------ class Handler(HandlerBase): From 28b19068aac829cdc2a3066c1242db0bedd45710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= <simon@stellanera.com> Date: Mon, 18 Jun 2012 10:47:02 +0200 Subject: [PATCH 0416/1590] add WYSIWYG editors section to page docs --- docs/page.rst | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/page.rst b/docs/page.rst index 7b77947c5..bd15f5a47 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -78,8 +78,8 @@ need to download `TinyMCE <http://www.tinymce.com/>`_ and configure FeinCMS' richtext support:: FEINCMS_RICHTEXT_INIT_CONTEXT = { - 'TINYMCE_JS_URL': STATIC_URL + 'your_custom_path/tiny_mce.js', - } + 'TINYMCE_JS_URL': MEDIA_URL + 'your_custom_path/tiny_mce.js', + } Wiring up the views @@ -302,6 +302,33 @@ for whatever purposes you have in mind. exactly like ``register_request_processor`` above. It behaves in the same way. +WYSIWYG Editors +=============== + +TinyMCE is configured by default to only allow for minimal formatting. This has proven +to be the best compromise between letting the client format text without destroying the +page design concept. You can customize the TinyMCE settings by creating your own +init_richtext.html that inherits from `admin/content/richtext/init_tinymce.html`. +You can even set your own css and linklist files like so:: + + FEINCMS_RICHTEXT_INIT_CONTEXT = { + 'TINYMCE_JS_URL': MEDIA_URL + 'your_custom_path/tiny_mce.js', + 'TINYMCE_CONTENT_CSS_URL': None, # add your css path here + 'TINYMCE_LINK_LIST_URL': None # add your linklist.js path here + } + +FeinCMS is set up to use TinyMCE_ but you can use CKEditor_ instead if you prefer +that one. Change the following settings:: + + FEINCMS_RICHTEXT_INIT_TEMPLATE = 'admin/content/richtext/init_ckeditor.html' + FEINCMS_RICHTEXT_INIT_CONTEXT = { + 'CKEDITOR_JS_URL': MEDIA_URL + 'path_to_your/ckeditor.js') + } + +.. _TinyMCE: http://www.tinymce.com/ +.. _CKEditor: http://ckeditor.com/ + + ETag handling ============= From 1e570feedbd2a33acdac3ebbe47a14bc59c09640 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 10:55:20 +0200 Subject: [PATCH 0417/1590] Exclude pages with inactive parents in manager methods The old handling where the activity check was run in code which belongs to the request-response cycle (but still was inside the models file!) was arguably broken. This commit adds a new argument to all page manager methods, require_path_active, which replaces the functionality of require_path_active_request_processor. --- feincms/context_processors.py | 5 +- feincms/module/extensions/translations.py | 3 +- feincms/module/page/models.py | 57 ++++++++++++++++++++--- feincms/tests/page_tests.py | 11 +++-- feincms/views/cbv/views.py | 3 +- 5 files changed, 67 insertions(+), 12 deletions(-) diff --git a/feincms/context_processors.py b/feincms/context_processors.py index a74385c3a..e7532c6fe 100644 --- a/feincms/context_processors.py +++ b/feincms/context_processors.py @@ -10,7 +10,10 @@ def add_page_if_missing(request): try: return { - 'feincms_page': Page.objects.for_request(request, best_match=True), + 'feincms_page': Page.objects.for_request(request, + best_match=True, + setup=False, + require_path_active=True), } except Page.DoesNotExist: return {} diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 044756418..77cba04ef 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -145,7 +145,8 @@ def get_redirect_to_target(self, request): target = self.redirect_to if target and target.find('//') == -1: # Not an offsite link http://bla/blubb try: - page = cls.objects.page_for_path(target) + page = cls.objects.page_for_path(target, + require_path_active=True) page = page.get_translation(get_current_language_code(request)) target = page.get_absolute_url() except cls.DoesNotExist: diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 7bc0ffc9c..839d586ce 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -2,6 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ +import warnings import re from django.core.cache import cache as django_cache @@ -33,7 +34,7 @@ class PageManager(models.Manager, ActiveAwareContentManagerMixin): # The fields which should be excluded when creating a copy. exclude_from_copy = ['id', 'tree_id', 'lft', 'rght', 'level', 'redirect_to'] - def page_for_path(self, path, raise404=False): + def page_for_path(self, path, raise404=False, require_path_active=False): """ Return a page for a path. Optionally raises a 404 error if requested. @@ -42,16 +43,31 @@ def page_for_path(self, path, raise404=False): Page.objects.page_for_path(request.path) """ + if not require_path_active: + warnings.warn( + 'Calling page_for_path with require_path_active=False is' + ' discouraged. require_path_active will default to True in' + ' FeinCMS v1.8.', + DeprecationWarning, stacklevel=2) + stripped = path.strip('/') try: - return self.active().get(_cached_url=stripped and u'/%s/' % stripped or '/') + page = self.active().get( + _cached_url=u'/%s/' % stripped if stripped else '/') + + if require_path_active and not page.are_ancestors_active(): + raise self.model.DoesNotExist('Parents are inactive.') + + return page + except self.model.DoesNotExist: if raise404: raise Http404 raise - def best_match_for_path(self, path, raise404=False): + def best_match_for_path(self, path, raise404=False, + require_path_active=False): """ Return the best match for a path. If the path as given is unavailable, continues to search by chopping path components off the end. @@ -63,6 +79,13 @@ def best_match_for_path(self, path, raise404=False): page with url '/photos/album/'. """ + if not require_path_active: + warnings.warn( + 'Calling best_match_for_path with require_path_active=False is' + ' discouraged. require_path_active will default to True in' + ' FeinCMS v1.8.', + DeprecationWarning, stacklevel=2) + paths = ['/'] path = path.strip('/') @@ -82,8 +105,13 @@ def best_match_for_path(self, path, raise404=False): try: page = self.active().filter(_cached_url__in=paths).extra( select={'_url_length': 'LENGTH(_cached_url)'}).order_by('-_url_length')[0] + + if require_path_active and not page.are_ancestors_active(): + raise IndexError('Parents are inactive.') + django_cache.set(ck, page) return page + except IndexError: if raise404: raise Http404 @@ -104,7 +132,8 @@ def toplevel_navigation(self): return self.in_navigation().filter(parent__isnull=True) - def for_request(self, request, raise404=False, best_match=False, setup=True): + def for_request(self, request, raise404=False, best_match=False, + setup=True, require_path_active=False): """ Return a page for the request @@ -118,15 +147,31 @@ def for_request(self, request, raise404=False, best_match=False, setup=True): could be determined. """ + if not require_path_active: + warnings.warn( + 'Calling for_request with require_path_active=False is' + ' discouraged. require_path_active will default to True in' + ' FeinCMS v1.8.', + DeprecationWarning, stacklevel=2) + if not hasattr(request, '_feincms_page'): path = request.path_info or request.path if best_match: - request._feincms_page = self.best_match_for_path(path, raise404=raise404) + request._feincms_page = self.best_match_for_path(path, + raise404=raise404, require_path_active=require_path_active) else: - request._feincms_page = self.page_for_path(path, raise404=raise404) + request._feincms_page = self.page_for_path(path, + raise404=raise404, require_path_active=require_path_active) if setup: + warnings.warn( + 'Calling for_request with setup=True is discouraged. setup' + ' will do nothing in FeinCMS v1.8 and the parameter will be' + ' removed. Use require_path_active and active_filters or' + ' the appropriate request processors instead.', + DeprecationWarning, stacklevel=2) + request._feincms_page.setup_request(request) return request._feincms_page diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 505f445d5..ff2596dd5 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -887,16 +887,21 @@ def test_19_page_manager(self): page.active = False page.save() - self.assertRaises(Http404, lambda: Page.objects.for_request(request, raise404=True)) + self.assertRaises(Http404, + lambda: Page.objects.for_request(request, raise404=True, + require_path_active=True)) page.active = True page.save() - self.assertRaises(Http404, lambda: Page.objects.for_request(request, raise404=True)) + self.assertRaises(Http404, + lambda: Page.objects.for_request(request, raise404=True, + require_path_active=True)) page.parent.active = True page.parent.save() - self.assertEqual(page, Page.objects.for_request(request)) + self.assertEqual(page, Page.objects.for_request(request, + require_path_active=True)) old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH request.path += 'hello/' diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 0c6e51306..98f8fbbb1 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -20,7 +20,8 @@ def post(self, request, *args, **kwargs): def handler(self, request, *args, **kwargs): page = Page.objects.for_request(request, - raise404=True, best_match=True, setup=False) + raise404=True, best_match=True, setup=False, + require_path_active=True) return self.handle_object(page) From 715cc59c9ffc3698a492402976cde1e13ffeb522 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 11:33:14 +0200 Subject: [PATCH 0418/1590] Remove the legacy views code --- docs/api/views.rst | 12 ---- feincms/views/legacy/__init__.py | 0 feincms/views/legacy/urls.py | 8 --- feincms/views/legacy/views.py | 110 ------------------------------- 4 files changed, 130 deletions(-) delete mode 100644 feincms/views/legacy/__init__.py delete mode 100644 feincms/views/legacy/urls.py delete mode 100644 feincms/views/legacy/views.py diff --git a/docs/api/views.rst b/docs/api/views.rst index 0eac21093..0f2d14a2f 100644 --- a/docs/api/views.rst +++ b/docs/api/views.rst @@ -1,23 +1,11 @@ Views and decorators ==================== - -Standard views --------------- - .. automodule:: feincms.views.cbv.views :members: :noindex: -Legacy views ------------- - -.. automodule:: feincms.views.legacy.views - :members: - :noindex: - - Generic-views replacements -------------------------- diff --git a/feincms/views/legacy/__init__.py b/feincms/views/legacy/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/feincms/views/legacy/urls.py b/feincms/views/legacy/urls.py deleted file mode 100644 index a2b60727e..000000000 --- a/feincms/views/legacy/urls.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.conf.urls import patterns, url - -from feincms.views.legacy.views import handler - -urlpatterns = patterns('', - url(r'^$', handler, name='feincms_home'), - url(r'^(.*)/$', handler, name='feincms_handler'), -) diff --git a/feincms/views/legacy/views.py b/feincms/views/legacy/views.py deleted file mode 100644 index a6f8b2aa3..000000000 --- a/feincms/views/legacy/views.py +++ /dev/null @@ -1,110 +0,0 @@ -from django.http import Http404 -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.utils.cache import add_never_cache_headers - -from feincms import settings -from feincms.module.page.models import Page - - -class Handler(object): - """ - This is the legacy handler for feincms page content. - - It isn't a class-based-view like those in Django's generic view framework. - State should not be stored on the ``Handler`` class, because of thread-safety - and cross polination issues. - """ - - def __call__(self, request, path=None): - return self.build_response(request, - Page.objects.best_match_for_path(path or request.path, raise404=True)) - - def build_response(self, request, page): - """ - Calls `prepare`, `render` and `finalize`, in this order. - """ - - response = self.prepare(request, page) - if response: - return response - - response = self.render(request, page) - return self.finalize(request, response, page) - - def prepare(self, request, page): - """ - Prepare / pre-process content types. If this method returns anything, - it is treated as a ``HttpResponse`` and handed back to the visitor. - """ - - response = page.setup_request(request) - if response: - return response - - http404 = None # store eventual Http404 exceptions for re-raising, - # if no content type wants to handle the current request - successful = False # did any content type successfully end processing? - - for content in page.content.all_of_type(tuple(page._feincms_content_types_with_process)): - try: - r = content.process(request) - if r in (True, False): - successful = r - elif r: - return r - except Http404, e: - http404 = e - - if not successful: - if http404: - # re-raise stored Http404 exception - raise http404 - - if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ - request._feincms_extra_context['extra_path'] != '/': - raise Http404 - - def render(self, request, page): - """ - The render step. Must return a HttpResponse. - """ - - # This facility can be used by request processors to add values - # to the context. - context = request._feincms_extra_context - context['feincms_page'] = page - - return render_to_response(page.template.path, - context_instance=RequestContext(request, context)) - - def finalize(self, request, response, page): - """ - Runs finalize() on content types having such a method, adds headers and - returns the final response. - """ - - for content in page.content.all_of_type(tuple(page._feincms_content_types_with_finalize)): - r = content.finalize(request, response) - if r: - return r - - page.finalize_response(request, response) - - # Add never cache headers in case frontend editing is active - if (hasattr(request, "COOKIES") - and request.COOKIES.get('frontend_editing')): - add_never_cache_headers(response) - - return response - - @property - def __name__(self): - """ - Dummy property to make this handler behave like a normal function. - This property is used by django-debug-toolbar - """ - return self.__class__.__name__ - -#: Default handler -handler = Handler() From e10d3dfc2f60e4a4cca9a7eb803460da1ab4c0f8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 11:34:33 +0200 Subject: [PATCH 0419/1590] Remove require_path_active argument and make behavior the default The existing behavior was clearly broken, and this change will be treated as a bug fix. --- feincms/context_processors.py | 5 +-- feincms/module/extensions/translations.py | 7 ++-- feincms/module/mixins.py | 9 +++-- feincms/module/page/models.py | 48 +++++------------------ feincms/module/page/processors.py | 9 ----- feincms/tests/page_tests.py | 9 ++--- feincms/views/cbv/views.py | 3 +- 7 files changed, 24 insertions(+), 66 deletions(-) diff --git a/feincms/context_processors.py b/feincms/context_processors.py index e7532c6fe..a74385c3a 100644 --- a/feincms/context_processors.py +++ b/feincms/context_processors.py @@ -10,10 +10,7 @@ def add_page_if_missing(request): try: return { - 'feincms_page': Page.objects.for_request(request, - best_match=True, - setup=False, - require_path_active=True), + 'feincms_page': Page.objects.for_request(request, best_match=True), } except Page.DoesNotExist: return {} diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 77cba04ef..acdb575be 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -3,8 +3,8 @@ # ------------------------------------------------------------------------ """ -This extension adds a language field to every page. When calling setup_request, -the page's language is activated. +This extension adds a language field to every page. When calling the request +processors the page's language is activated. Pages in secondary languages can be said to be a translation of a page in the primary language (the first language in settings.LANGUAGES), thereby enabling deeplinks between translated pages. @@ -145,8 +145,7 @@ def get_redirect_to_target(self, request): target = self.redirect_to if target and target.find('//') == -1: # Not an offsite link http://bla/blubb try: - page = cls.objects.page_for_path(target, - require_path_active=True) + page = cls.objects.page_for_path(target) page = page.get_translation(get_current_language_code(request)) target = page.get_absolute_url() except cls.DoesNotExist: diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 342b9b167..9cafa55f9 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -23,8 +23,11 @@ class ContentMixin(object): response_processors = SortedDict() def setup_request(self, request): - if not hasattr(request, '_feincms_extra_context'): - request._feincms_extra_context = {} + import warnings + warnings.warn( + '%s.setup_request does nothing anymore, and will be removed in' + ' FeinCMS v1.8', + DeprecationWarning, stacklevel=2) @classmethod def register_request_processor(cls, fn, key=None): @@ -56,7 +59,7 @@ def post(self, request, *args, **kwargs): def handler(self, request, *args, **kwargs): self.page = Page.objects.for_request(request, - raise404=True, best_match=True, setup=False) + raise404=True, best_match=True) def handle_object(self, object): if not hasattr(self.request, '_feincms_extra_context'): diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 839d586ce..7dd736766 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -2,7 +2,6 @@ # coding=utf-8 # ------------------------------------------------------------------------ -import warnings import re from django.core.cache import cache as django_cache @@ -34,7 +33,7 @@ class PageManager(models.Manager, ActiveAwareContentManagerMixin): # The fields which should be excluded when creating a copy. exclude_from_copy = ['id', 'tree_id', 'lft', 'rght', 'level', 'redirect_to'] - def page_for_path(self, path, raise404=False, require_path_active=False): + def page_for_path(self, path, raise404=False): """ Return a page for a path. Optionally raises a 404 error if requested. @@ -43,20 +42,13 @@ def page_for_path(self, path, raise404=False, require_path_active=False): Page.objects.page_for_path(request.path) """ - if not require_path_active: - warnings.warn( - 'Calling page_for_path with require_path_active=False is' - ' discouraged. require_path_active will default to True in' - ' FeinCMS v1.8.', - DeprecationWarning, stacklevel=2) - stripped = path.strip('/') try: page = self.active().get( _cached_url=u'/%s/' % stripped if stripped else '/') - if require_path_active and not page.are_ancestors_active(): + if not page.are_ancestors_active(): raise self.model.DoesNotExist('Parents are inactive.') return page @@ -66,8 +58,7 @@ def page_for_path(self, path, raise404=False, require_path_active=False): raise Http404 raise - def best_match_for_path(self, path, raise404=False, - require_path_active=False): + def best_match_for_path(self, path, raise404=False): """ Return the best match for a path. If the path as given is unavailable, continues to search by chopping path components off the end. @@ -79,13 +70,6 @@ def best_match_for_path(self, path, raise404=False, page with url '/photos/album/'. """ - if not require_path_active: - warnings.warn( - 'Calling best_match_for_path with require_path_active=False is' - ' discouraged. require_path_active will default to True in' - ' FeinCMS v1.8.', - DeprecationWarning, stacklevel=2) - paths = ['/'] path = path.strip('/') @@ -106,7 +90,7 @@ def best_match_for_path(self, path, raise404=False, page = self.active().filter(_cached_url__in=paths).extra( select={'_url_length': 'LENGTH(_cached_url)'}).order_by('-_url_length')[0] - if require_path_active and not page.are_ancestors_active(): + if not page.are_ancestors_active(): raise IndexError('Parents are inactive.') django_cache.set(ck, page) @@ -133,7 +117,7 @@ def toplevel_navigation(self): return self.in_navigation().filter(parent__isnull=True) def for_request(self, request, raise404=False, best_match=False, - setup=True, require_path_active=False): + setup=False): """ Return a page for the request @@ -147,32 +131,23 @@ def for_request(self, request, raise404=False, best_match=False, could be determined. """ - if not require_path_active: - warnings.warn( - 'Calling for_request with require_path_active=False is' - ' discouraged. require_path_active will default to True in' - ' FeinCMS v1.8.', - DeprecationWarning, stacklevel=2) - if not hasattr(request, '_feincms_page'): path = request.path_info or request.path if best_match: request._feincms_page = self.best_match_for_path(path, - raise404=raise404, require_path_active=require_path_active) + raise404=raise404) else: request._feincms_page = self.page_for_path(path, - raise404=raise404, require_path_active=require_path_active) + raise404=raise404): if setup: + import warnings warnings.warn( - 'Calling for_request with setup=True is discouraged. setup' - ' will do nothing in FeinCMS v1.8 and the parameter will be' - ' removed. Use require_path_active and active_filters or' - ' the appropriate request processors instead.', + 'Calling for_request with setup=True does nothing anymore.' + ' The parameter will be removed in FeinCMS v1.8.', DeprecationWarning, stacklevel=2) - request._feincms_page.setup_request(request) return request._feincms_page @@ -356,9 +331,6 @@ def path_to_cache_key(path): # ------------------------------------------------------------------------ # Our default request processors -Page.register_request_processor( - processors.require_path_active_request_processor, - key='path_active') Page.register_request_processor(processors.redirect_request_processor, key='redirect') diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index e3b66e80c..706e1ace9 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -4,15 +4,6 @@ from django.http import Http404, HttpResponseRedirect -def require_path_active_request_processor(page, request): - """ - Checks whether any ancestors are actually inaccessible (ie. not - inactive or expired) and raise a 404 if so. - """ - if not page.are_ancestors_active(): - raise Http404() - - def redirect_request_processor(page, request): """ Returns a ``HttpResponseRedirect`` instance if the current page says diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index ff2596dd5..868d27589 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -888,20 +888,17 @@ def test_19_page_manager(self): page.save() self.assertRaises(Http404, - lambda: Page.objects.for_request(request, raise404=True, - require_path_active=True)) + lambda: Page.objects.for_request(request, raise404=True)) page.active = True page.save() self.assertRaises(Http404, - lambda: Page.objects.for_request(request, raise404=True, - require_path_active=True)) + lambda: Page.objects.for_request(request, raise404=True)) page.parent.active = True page.parent.save() - self.assertEqual(page, Page.objects.for_request(request, - require_path_active=True)) + self.assertEqual(page, Page.objects.for_request(request)) old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH request.path += 'hello/' diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 98f8fbbb1..0c6e51306 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -20,8 +20,7 @@ def post(self, request, *args, **kwargs): def handler(self, request, *args, **kwargs): page = Page.objects.for_request(request, - raise404=True, best_match=True, setup=False, - require_path_active=True) + raise404=True, best_match=True, setup=False) return self.handle_object(page) From 000d00859ba11f01ab87b3ed8908eedebf95cbf1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 11:40:01 +0200 Subject: [PATCH 0420/1590] Remove obsolete replacement of path_active request processor in preview view --- feincms/contrib/preview/views.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 967faf9f6..3773f06d5 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -20,13 +20,6 @@ def handler(self, request, path, page_id): page = get_object_or_404(Page, pk=page_id) - # Throw out request processor which will cause the page to-be-previewed - # to be seen as inactive (which is the case, of course) - page.request_processors = page.request_processors.copy() - page.register_request_processor( - lambda page, response: None, # Do nothing - key='path_active') - # Remove _preview/42/ from URL, the rest of the handler code should not # know that anything about previewing. Handler.prepare will still raise # a 404 if the extra_path isn't consumed by any content type From 0c55aa8ed1c621192dadde38e7b7a5167fe824b4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 11:43:28 +0200 Subject: [PATCH 0421/1590] Typofix --- feincms/module/page/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 7dd736766..d9d4e813f 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -139,7 +139,7 @@ def for_request(self, request, raise404=False, best_match=False, raise404=raise404) else: request._feincms_page = self.page_for_path(path, - raise404=raise404): + raise404=raise404) if setup: import warnings From 9eae63e74908f4e3c6ab2488be5dfcfa5f33f1ca Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 11:48:10 +0200 Subject: [PATCH 0422/1590] Adapt tests to changed page manager behavior --- feincms/tests/page_tests.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 868d27589..19b1b2890 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -864,13 +864,21 @@ def test_19_page_manager(self): page.active = True page.save() - self.assertEqual(page, Page.objects.page_for_path(page.get_absolute_url())) - self.assertEqual(page, Page.objects.best_match_for_path(page.get_absolute_url() + 'something/hello/')) + self.assertRaises(Page.DoesNotExist, + lambda: Page.objects.page_for_path(page.get_absolute_url())) + self.assertRaises(Page.DoesNotExist, + lambda: Page.objects.best_match_for_path( + page.get_absolute_url() + 'something/hello/')) - self.assertRaises(Http404, lambda: Page.objects.best_match_for_path('/blabla/blabla/', raise404=True)) - self.assertRaises(Http404, lambda: Page.objects.page_for_path('/asdf/', raise404=True)) - self.assertRaises(Page.DoesNotExist, lambda: Page.objects.best_match_for_path('/blabla/blabla/')) - self.assertRaises(Page.DoesNotExist, lambda: Page.objects.page_for_path('/asdf/')) + self.assertRaises(Http404, + lambda: Page.objects.best_match_for_path( + '/blabla/blabla/', raise404=True)) + self.assertRaises(Http404, + lambda: Page.objects.page_for_path('/asdf/', raise404=True)) + self.assertRaises(Page.DoesNotExist, + lambda: Page.objects.best_match_for_path('/blabla/blabla/')) + self.assertRaises(Page.DoesNotExist, + lambda: Page.objects.page_for_path('/asdf/')) request = Empty() request.path = request.path_info = page.get_absolute_url() @@ -900,6 +908,12 @@ def test_19_page_manager(self): page.parent.save() self.assertEqual(page, Page.objects.for_request(request)) + self.assertEqual(page, + Page.objects.page_for_path(page.get_absolute_url())) + self.assertEqual(page, + Page.objects.best_match_for_path( + page.get_absolute_url() + 'something/hello/')) + old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH request.path += 'hello/' From 474ba7ec650deee9cee7fd1eecc60768614c9658 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 11:52:34 +0200 Subject: [PATCH 0423/1590] Raise Http404 instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Simon Bächler for the report. --- feincms/admin/item_editor.py | 2 +- feincms/contrib/preview/views.py | 2 +- feincms/module/mixins.py | 2 +- feincms/module/page/models.py | 4 ++-- feincms/module/page/processors.py | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 17317da8e..7d64d3d97 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -116,7 +116,7 @@ def _frontend_editing_view(self, request, cms_id, content_type, content_id): model_cls = loading.get_model(self.model._meta.app_label, content_type) obj = model_cls.objects.get(parent=cms_id, id=content_id) except: - raise Http404 + raise Http404() form_class_base = getattr(model_cls, 'feincms_item_editor_form', ItemEditorForm) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 3773f06d5..2c0fa8a4a 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -16,7 +16,7 @@ class PreviewHandler(Handler): def handler(self, request, path, page_id): if not request.user.is_staff: - raise Http404 + raise Http404() page = get_object_or_404(Page, pk=page_id) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 9cafa55f9..860d5f697 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -183,7 +183,7 @@ def process_content_types(self): if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ self.request._feincms_extra_context['extra_path'] != '/': - raise Http404 + raise Http404() def finalize_content_types(self, response): """ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index d9d4e813f..223541bcf 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -55,7 +55,7 @@ def page_for_path(self, path, raise404=False): except self.model.DoesNotExist: if raise404: - raise Http404 + raise Http404() raise def best_match_for_path(self, path, raise404=False): @@ -98,7 +98,7 @@ def best_match_for_path(self, path, raise404=False): except IndexError: if raise404: - raise Http404 + raise Http404() raise self.model.DoesNotExist diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 706e1ace9..3a5efb4a3 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -15,6 +15,7 @@ def redirect_request_processor(page, request): return HttpResponseRedirect(target) raise Http404() + def frontendediting_request_processor(page, request): """ Sets the frontend editing state in the session depending on the From 2397092b3a6564925ec85ccd5f5dccca3bfbc49e Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 18 Jun 2012 20:45:44 +1000 Subject: [PATCH 0424/1590] Expose ImageContent.format via image-content-format-... css class. --- feincms/templates/content/image/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templates/content/image/default.html b/feincms/templates/content/image/default.html index ad373ea30..64d795dec 100644 --- a/feincms/templates/content/image/default.html +++ b/feincms/templates/content/image/default.html @@ -1 +1 @@ -<div class="image-content image-content-{{ content.position }}"><img src="{{ content.get_image.url }}" alt="{{ content.alt_text }}" />{% if content.caption %}<div class="caption">{{ content.caption }}</div>{% endif %}</div> +<div class="image-content image-content-{{ content.position }}{% if content.format %} image-content-format-{{ content.format|slugify }}{% endif %}"><img src="{{ content.get_image.url }}" alt="{{ content.alt_text }}" />{% if content.caption %}<div class="caption">{{ content.caption }}</div>{% endif %}</div> From 332dd96c5d3b7d2e79c069b6609ad0b604f8721c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 12:49:12 +0200 Subject: [PATCH 0425/1590] Start refactoring the extensions mechanism Refs #297. --- feincms/admin/item_editor.py | 3 +- feincms/admin/tree_editor.py | 3 +- feincms/extensions.py | 161 ++++++++++++++++++++++++++++++++++ feincms/models.py | 78 +--------------- feincms/module/page/models.py | 8 -- 5 files changed, 167 insertions(+), 86 deletions(-) create mode 100644 feincms/extensions.py diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 17317da8e..46f380232 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -17,6 +17,7 @@ from django.contrib.admin.options import InlineModelAdmin from feincms import settings, ensure_completely_loaded +from feincms.extensions import ExtensionModelAdmin from feincms.signals import itemeditor_post_save_related # ------------------------------------------------------------------------ @@ -46,7 +47,7 @@ class FeinCMSInline(InlineModelAdmin): template = 'admin/feincms/content_inline.html' # ------------------------------------------------------------------------ -class ItemEditor(admin.ModelAdmin): +class ItemEditor(ExtensionModelAdmin): """ The ``ItemEditor`` is a drop-in replacement for ``ModelAdmin`` with the speciality of knowing how to work with :class:`feincms.models.Base` diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 12e7ff3db..0fab1ae47 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -17,6 +17,7 @@ from mptt.forms import MPTTAdminForm from feincms import settings +from feincms.extensions import ExtensionModelAdmin # ------------------------------------------------------------------------ @@ -160,7 +161,7 @@ def get_results(self, request): # MARK: - # ------------------------------------------------------------------------ -class TreeEditor(admin.ModelAdmin): +class TreeEditor(ExtensionModelAdmin): """ The ``TreeEditor`` modifies the standard Django administration change list to a drag-drop enabled interface for django-mptt_-managed Django models. diff --git a/feincms/extensions.py b/feincms/extensions.py new file mode 100644 index 000000000..e3f11a122 --- /dev/null +++ b/feincms/extensions.py @@ -0,0 +1,161 @@ +""" +Base types for extensions refactor +""" + +import warnings + +from django.contrib import admin + +from feincms.utils import get_object + + +class ExtensionsMixin(object): + @classmethod + def register_extensions(cls, *extensions): + """ + Register all extensions passed as arguments. + + Extensions should be specified as a string to the python module + containing the extension. If it is a bundled extension of FeinCMS, + you do not need to specify the full python module path -- only + specifying the last part (f.e. ``'seo'`` or ``'translations'``) is + sufficient. + """ + + if not hasattr(cls, '_extensions'): + cls._extensions = [] + + if not hasattr(cls, '_feincms_extensions'): + cls._feincms_extensions = set() + + here = cls.__module__.split('.')[:-1] + + paths = [ + '.'.join(here + ['extensions']), + '.'.join(here[:-1] + ['extensions']), + 'feincms.module.extensions', + ] + + for ext in extensions: + if ext in cls._feincms_extensions: + continue + + fn = None + if isinstance(ext, basestring): + try: + fn = get_object(ext + '.register') + except ImportError: + for path in paths: + try: + fn = get_object('%s.%s.register' % (path, ext)) + if fn: + warnings.warn( + 'Using short names for extensions has been' + ' deprecated and will be removed in' + ' FeinCMS v1.8. Please provide the full' + ' python path to the extension' + ' %s instead (%s.%s).' % (ext, path, ext), + DeprecationWarning, stacklevel=2) + + break + except ImportError: + pass + + if not fn: + raise ImproperlyConfigured( + '%s is not a valid extension for %s' % ( + ext, cls.__name__)) + + # Not a string, maybe a callable? + elif hasattr(ext, '__call__'): + fn = ext + + elif hasattr(ext, 'register'): + fn = ext.register + + + if isinstance(ext, type) and issubclass(ext, Extension): + cls._extensions.append(ext(cls)) + cls._feincms_extensions.append(ext.ident) + else: + cls._extensions.append(OldSchoolExtension(cls, extension=fn)) + cls._feincms_extensions.add(ext) + + +class Extension(object): + #: Unique identifier for this extension, will be added + #: to ``cls._feincms_extensions`` to prevent double registration + ident = '' + + def __init__(self, model, **kwargs): + self.model = model + for key, value in kwargs.items(): + if not hasattr(self, key): + raise TypeError('%s() received an invalid keyword %r' % ( + self.__class__.__name__, key)) + setattr(self, key, value) + + self.handle_model() + + def handle_model(self, model): + raise NotImplementedError + + def handle_modeladmin(self, modeladmin): + pass + + +class OldSchoolExtension(Extension): + """ + Wrapper for old-school extensions + """ + + #: Old-school extension function + extension = None + + def handle_model(self): + self.fieldsets = [] + self.list_display = [] + self.list_filter = [] + self.search_fields = [] + + self.extension(self.model, self) + + def handle_modeladmin(self, modeladmin): + if self.fieldsets: + modeladmin.fieldsets.extend(self.fieldsets) + if self.list_display: + modeladmin.list_display.extend(self.list_display) + if self.list_filter: + modeladmin.list_filter.extend(self.list_filter) + if self.search_fields: + modeladmin.search_fields.extend(self.search_fields) + + @classmethod + def add_extension_options(cls, *f): + if isinstance(f[-1], dict): # called with a fieldset + cls.fieldsets.insert(cls.fieldset_insertion_index, f) + f[1]['classes'] = list(f[1].get('classes', [])) + f[1]['classes'].append('collapse') + else: # assume called with "other" fields + cls.fieldsets[1][1]['fields'].extend(f) + + +class ExtensionModelAdmin(admin.ModelAdmin): + def __init__(self, *args, **kwargs): + super(ExtensionModelAdmin, self).__init__(*args, **kwargs) + self.initialize_extensions() + + def initialize_extensions(self): + if not hasattr(self, '_extensions_initialized'): + self._extensions_initialized = True + for extension in getattr(self.model, '_extensions', []): + extension.handle_modeladmin(self) + + @classmethod + def add_extension_options(cls, *f): + if isinstance(f[-1], dict): # called with a fieldset + cls.fieldsets.insert(cls.fieldset_insertion_index, f) + f[1]['classes'] = list(f[1].get('classes', [])) + f[1]['classes'].append('collapse') + else: # assume called with "other" fields + cls.fieldsets[1][1]['fields'].extend(f) diff --git a/feincms/models.py b/feincms/models.py index f2aaf9a60..28221e2e8 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -21,7 +21,8 @@ from django.utils.translation import ugettext_lazy as _ from feincms import ensure_completely_loaded -from feincms.utils import get_object, copy_model_instance +from feincms.extensions import ExtensionsMixin +from feincms.utils import copy_model_instance class Region(object): @@ -278,81 +279,6 @@ def __getattr__(self, attr): return self._fetch_regions().get(attr, []) -class ExtensionsMixin(object): - @classmethod - def register_extension(cls, register_fn): - """ - Call the register function of an extension. You must override this - if you provide a custom ModelAdmin class and want your extensions to - be able to patch stuff in. - """ - register_fn(cls, None) - - @classmethod - def register_extensions(cls, *extensions): - """ - Register all extensions passed as arguments. - - Extensions should be specified as a string to the python module - containing the extension. If it is a bundled extension of FeinCMS, - you do not need to specify the full python module path -- only - specifying the last part (f.e. ``'seo'`` or ``'translations'``) is - sufficient. - """ - - if not hasattr(cls, '_feincms_extensions'): - cls._feincms_extensions = set() - - here = cls.__module__.split('.')[:-1] - - paths = [ - '.'.join(here + ['extensions']), - '.'.join(here[:-1] + ['extensions']), - 'feincms.module.extensions', - ] - - for ext in extensions: - if ext in cls._feincms_extensions: - continue - - fn = None - if isinstance(ext, basestring): - try: - fn = get_object(ext + '.register') - except ImportError: - for path in paths: - try: - fn = get_object('%s.%s.register' % (path, ext)) - if fn: - warnings.warn( - 'Using short names for extensions has been' - ' deprecated and will be removed in' - ' FeinCMS v1.8. Please provide the full' - ' python path to the extension' - ' %s instead (%s.%s).' % (ext, path, ext), - DeprecationWarning, stacklevel=2) - - break - except ImportError: - pass - - if not fn: - raise ImproperlyConfigured( - '%s is not a valid extension for %s' % ( - ext, cls.__name__)) - - # Not a string, maybe a callable? - elif hasattr(ext, '__call__'): - fn = ext - - # Take our chances and just try to access "register" - else: - fn = ext.register - - cls.register_extension(fn) - cls._feincms_extensions.add(ext) - - def create_base_model(inherit_from=models.Model): """ This method can be used to create a FeinCMS base model inheriting from diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 969905113..4ffc5866a 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -374,10 +374,6 @@ def register_response_processor(cls, fn, key=None): """ cls.response_processors[fn if key is None else key] = fn - @classmethod - def register_extension(cls, register_fn): - register_fn(cls, PageAdmin) - @staticmethod def path_to_cache_key(path): return path_to_cache_key(path.strip('/'), prefix="PAGE-FOR-URL") @@ -396,9 +392,5 @@ def path_to_cache_key(path): signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) -# ------------------------------------------------------------------------ -# Down here as to avoid circular imports -from .modeladmins import PageAdmin - # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ From bd5810ab59e0a3d558448b4099d02f9dd2c7c5ce Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 13:25:26 +0200 Subject: [PATCH 0426/1590] Refactor extension discovery --- feincms/extensions.py | 86 +++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index e3f11a122..d50136f33 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -5,6 +5,7 @@ import warnings from django.contrib import admin +from django.core.exceptions import ImproperlyConfigured from feincms.utils import get_object @@ -29,8 +30,7 @@ def register_extensions(cls, *extensions): cls._feincms_extensions = set() here = cls.__module__.split('.')[:-1] - - paths = [ + search_paths = [ '.'.join(here + ['extensions']), '.'.join(here[:-1] + ['extensions']), 'feincms.module.extensions', @@ -40,45 +40,53 @@ def register_extensions(cls, *extensions): if ext in cls._feincms_extensions: continue - fn = None + extension = None + if isinstance(ext, basestring): - try: - fn = get_object(ext + '.register') - except ImportError: - for path in paths: - try: - fn = get_object('%s.%s.register' % (path, ext)) - if fn: - warnings.warn( - 'Using short names for extensions has been' - ' deprecated and will be removed in' - ' FeinCMS v1.8. Please provide the full' - ' python path to the extension' - ' %s instead (%s.%s).' % (ext, path, ext), - DeprecationWarning, stacklevel=2) - - break - except ImportError: - pass - - if not fn: - raise ImproperlyConfigured( - '%s is not a valid extension for %s' % ( - ext, cls.__name__)) - - # Not a string, maybe a callable? - elif hasattr(ext, '__call__'): - fn = ext - - elif hasattr(ext, 'register'): - fn = ext.register - - - if isinstance(ext, type) and issubclass(ext, Extension): - cls._extensions.append(ext(cls)) - cls._feincms_extensions.append(ext.ident) + paths = [ext, '%s.register' % ext] + [ + '%s.%s.register' % (path, ext) for path in search_paths] + + for path in paths: + try: + extension = get_object(path) + break + except (AttributeError, ImportError): + pass + + """ + warnings.warn( + 'Using short names for extensions has been' + ' deprecated and will be removed in' + ' FeinCMS v1.8. Please provide the full' + ' python path to the extension' + ' %s instead (%s.%s).' % (ext, path, ext), + DeprecationWarning, stacklevel=2) + """ + + if not extension: + raise ImproperlyConfigured( + '%s is not a valid extension for %s' % ( + ext, cls.__name__)) + + if hasattr(extension, 'register'): + extension = extension.register + + elif hasattr(extension, 'Extension'): + extension = extension.Extension + + elif hasattr(extension, '__call__'): + pass + + else: + raise ImproperlyConfigured( + '%s is not a valid extension for %s' % ( + ext, cls.__name__)) + + if hasattr(extension, 'ident'): + cls._extensions.append(extension(cls)) + cls._feincms_extensions.add(extension.ident) else: - cls._extensions.append(OldSchoolExtension(cls, extension=fn)) + cls._extensions.append(OldSchoolExtension(cls, extension=extension)) cls._feincms_extensions.add(ext) From 1e5ca3d358d10be8d40f12f200ace10d1471a278 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 13:25:33 +0200 Subject: [PATCH 0427/1590] Rewrite navigation extension as a new-style Extension class --- feincms/module/page/extensions/navigation.py | 41 ++++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 88ccbd4e9..5d4a6feb3 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -10,6 +10,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions from feincms.utils import get_object from feincms._internal import monkeypatch_method @@ -90,23 +91,31 @@ def navigation_extension_choices(): yield ('%s.%s' % (ext.__module__, ext.__name__), ext.name) -def register(cls, admin_cls): - cls.add_to_class('navigation_extension', models.CharField(_('navigation extension'), - choices=navigation_extension_choices(), blank=True, null=True, max_length=200, - help_text=_('Select the module providing subpages for this page if you need to customize the navigation.'))) +class Extension(extensions.Extension): + ident = 'navigation' - @monkeypatch_method(cls) - def extended_navigation(self, **kwargs): - if not self.navigation_extension: - return self.children.in_navigation() + def handle_model(self): + self.model.add_to_class('navigation_extension', + models.CharField( + _('navigation extension'), + choices=navigation_extension_choices(), + blank=True, null=True, max_length=200, + help_text=_('Select the module providing subpages for this page if you need to customize the navigation.'))) - cls = get_object(self.navigation_extension, fail_silently=True) - if not cls or not callable(cls): - return self.children.in_navigation() + @monkeypatch_method(self.model) + def extended_navigation(self, **kwargs): + if not self.navigation_extension: + return self.children.in_navigation() - return cls().children(self, **kwargs) + cls = get_object(self.navigation_extension, fail_silently=True) + if not cls or not callable(cls): + return self.children.in_navigation() - admin_cls.fieldsets.append((_('Navigation extension'), { - 'fields': ('navigation_extension',), - 'classes': ('collapse',), - })) + return cls().children(self, **kwargs) + + + def handle_modeladmin(self, modeladmin): + modeladmin.add_extension_options(_('Navigation extension'), { + 'fields': ('navigation_extension',), + 'classes': ('collapse',), + }) From 326572be2e27c6106024b0924417fde327ca1f8f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 13:28:43 +0200 Subject: [PATCH 0428/1590] Rename old-school extensions to legacy extensions --- feincms/extensions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index d50136f33..3f79e28f9 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -86,7 +86,7 @@ def register_extensions(cls, *extensions): cls._extensions.append(extension(cls)) cls._feincms_extensions.add(extension.ident) else: - cls._extensions.append(OldSchoolExtension(cls, extension=extension)) + cls._extensions.append(LegacyExtension(cls, extension=extension)) cls._feincms_extensions.add(ext) @@ -112,12 +112,12 @@ def handle_modeladmin(self, modeladmin): pass -class OldSchoolExtension(Extension): +class LegacyExtension(Extension): """ - Wrapper for old-school extensions + Wrapper for legacy extensions """ - #: Old-school extension function + #: Legacy extension function extension = None def handle_model(self): From fe7b278f36b8597c42d92838e41666ddae10d3ec Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 13:32:50 +0200 Subject: [PATCH 0429/1590] feincms_nav: Do not peek into _feincms_navigation --- feincms/module/page/templatetags/feincms_page_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index d87d60534..1badbd99d 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -81,7 +81,7 @@ def _filter(iterable): queryset = _filter(queryset) - if 'navigation' in feincms_page._feincms_extensions: + if hasattr(feincms_page, 'navigation_extension'): # Filter out children of nodes which have a navigation extension extended_node_rght = [] # mptt node right value From 41f8356daf00e7eae1c5fc40379fbe7afc14135a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 13:39:19 +0200 Subject: [PATCH 0430/1590] Stop using _feincms_extensions --- feincms/extensions.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 3f79e28f9..66af0ebb9 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -11,6 +11,15 @@ class ExtensionsMixin(object): + @property + def _feincms_extensions(self): + warnings.warn( + 'Start using _extensions instead of _feincms_extensions' + ' today!', + DeprecationWarning, stacklevel=2) + + return set(self._extensions) + @classmethod def register_extensions(cls, *extensions): """ @@ -26,9 +35,6 @@ def register_extensions(cls, *extensions): if not hasattr(cls, '_extensions'): cls._extensions = [] - if not hasattr(cls, '_feincms_extensions'): - cls._feincms_extensions = set() - here = cls.__module__.split('.')[:-1] search_paths = [ '.'.join(here + ['extensions']), @@ -37,7 +43,7 @@ def register_extensions(cls, *extensions): ] for ext in extensions: - if ext in cls._feincms_extensions: + if ext in cls._extensions: continue extension = None @@ -84,17 +90,11 @@ def register_extensions(cls, *extensions): if hasattr(extension, 'ident'): cls._extensions.append(extension(cls)) - cls._feincms_extensions.add(extension.ident) else: cls._extensions.append(LegacyExtension(cls, extension=extension)) - cls._feincms_extensions.add(ext) class Extension(object): - #: Unique identifier for this extension, will be added - #: to ``cls._feincms_extensions`` to prevent double registration - ident = '' - def __init__(self, model, **kwargs): self.model = model for key, value in kwargs.items(): From 9b77366374b9d0c43c862693bbf710dd442dfdb7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 13:39:36 +0200 Subject: [PATCH 0431/1590] Add deprecation warning back for extension shorthands --- feincms/extensions.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 66af0ebb9..70754b884 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -2,6 +2,7 @@ Base types for extensions refactor """ +import re import warnings from django.contrib import admin @@ -52,34 +53,37 @@ def register_extensions(cls, *extensions): paths = [ext, '%s.register' % ext] + [ '%s.%s.register' % (path, ext) for path in search_paths] - for path in paths: + for idx, path in enumerate(paths): try: extension = get_object(path) + + if idx >= 2: + warnings.warn( + 'Using short names for extensions has been' + ' deprecated and will be removed in' + ' FeinCMS v1.8. Please provide the full' + ' python path to the extension' + ' %s instead (%s).' % ( + ext, + re.sub(r'\.register$', '', path), + ), + DeprecationWarning, stacklevel=2) + break - except (AttributeError, ImportError): + except (AttributeError, ImportError, ValueError): pass - """ - warnings.warn( - 'Using short names for extensions has been' - ' deprecated and will be removed in' - ' FeinCMS v1.8. Please provide the full' - ' python path to the extension' - ' %s instead (%s.%s).' % (ext, path, ext), - DeprecationWarning, stacklevel=2) - """ - if not extension: raise ImproperlyConfigured( '%s is not a valid extension for %s' % ( ext, cls.__name__)) - if hasattr(extension, 'register'): - extension = extension.register - - elif hasattr(extension, 'Extension'): + if hasattr(extension, 'Extension'): extension = extension.Extension + elif hasattr(extension, 'register'): + extension = extension.register + elif hasattr(extension, '__call__'): pass From 68ceb1f4e3929180bc3d6eaefacec4623caf62c6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 13:47:11 +0200 Subject: [PATCH 0432/1590] Legacy extensions: Handle add_extension_options and raw_id_fields --- feincms/extensions.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 70754b884..317518161 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -128,8 +128,11 @@ def handle_model(self): self.fieldsets = [] self.list_display = [] self.list_filter = [] + self.raw_id_fields = [] self.search_fields = [] + self.extension_options = [] + self.extension(self.model, self) def handle_modeladmin(self, modeladmin): @@ -139,17 +142,18 @@ def handle_modeladmin(self, modeladmin): modeladmin.list_display.extend(self.list_display) if self.list_filter: modeladmin.list_filter.extend(self.list_filter) + if self.raw_id_fields: + modeladmin.raw_id_fields.extend(self.raw_id_fields) if self.search_fields: modeladmin.search_fields.extend(self.search_fields) - @classmethod - def add_extension_options(cls, *f): - if isinstance(f[-1], dict): # called with a fieldset - cls.fieldsets.insert(cls.fieldset_insertion_index, f) - f[1]['classes'] = list(f[1].get('classes', [])) - f[1]['classes'].append('collapse') - else: # assume called with "other" fields - cls.fieldsets[1][1]['fields'].extend(f) + if self.extension_options: + for f in self.extension_options: + modeladmin.add_extension_options(f) + + def add_extension_options(self, *f): + if f: + self.extension_options.append(f) class ExtensionModelAdmin(admin.ModelAdmin): From f11e1c6aa823a412a7eac26e187963efb9824a67 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 14:21:38 +0200 Subject: [PATCH 0433/1590] Prevent extensions from being registered twice --- feincms/extensions.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 317518161..b1bda1592 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -35,6 +35,7 @@ def register_extensions(cls, *extensions): if not hasattr(cls, '_extensions'): cls._extensions = [] + cls._extensions_seen = [] here = cls.__module__.split('.')[:-1] search_paths = [ @@ -92,7 +93,11 @@ def register_extensions(cls, *extensions): '%s is not a valid extension for %s' % ( ext, cls.__name__)) - if hasattr(extension, 'ident'): + if extension in cls._extensions_seen: + continue + cls._extensions_seen.append(extension) + + if hasattr(extension, 'handle_model'): cls._extensions.append(extension(cls)) else: cls._extensions.append(LegacyExtension(cls, extension=extension)) From 522afd01756c505b7200155ac0c7e12948998cf5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 14:23:03 +0200 Subject: [PATCH 0434/1590] Fix LegacyExtension to work with datepublisher --- feincms/extensions.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index b1bda1592..433560eaa 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -137,6 +137,7 @@ def handle_model(self): self.search_fields = [] self.extension_options = [] + self.known_keys = self.__dict__.keys() self.extension(self.model, self) @@ -154,7 +155,11 @@ def handle_modeladmin(self, modeladmin): if self.extension_options: for f in self.extension_options: - modeladmin.add_extension_options(f) + modeladmin.add_extension_options(*f) + + for key, value in self.__dict__.items(): + if key not in self.known_keys: + setattr(modeladmin.__class__, key, value) def add_extension_options(self, *f): if f: @@ -172,11 +177,10 @@ def initialize_extensions(self): for extension in getattr(self.model, '_extensions', []): extension.handle_modeladmin(self) - @classmethod - def add_extension_options(cls, *f): + def add_extension_options(self, *f): if isinstance(f[-1], dict): # called with a fieldset - cls.fieldsets.insert(cls.fieldset_insertion_index, f) + self.fieldsets.insert(self.fieldset_insertion_index, f) f[1]['classes'] = list(f[1].get('classes', [])) f[1]['classes'].append('collapse') - else: # assume called with "other" fields - cls.fieldsets[1][1]['fields'].extend(f) + elif f and self.fieldsets: # assume called with "other" fields + self.fieldsets[1][1]['fields'].extend(f) From c3c6ca63fa644e948269bb1a3103d90250f41e41 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 14:33:55 +0200 Subject: [PATCH 0435/1590] Convert extensions to add_extension_options, additional legacy support --- feincms/extensions.py | 6 + feincms/module/extensions/featured.py | 4 +- feincms/module/extensions/seo.py | 11 +- feincms/module/extensions/translations.py | 179 +++++++++--------- feincms/module/page/extensions/excerpt.py | 4 +- .../module/page/extensions/relatedpages.py | 4 +- feincms/module/page/extensions/sites.py | 1 + feincms/module/page/extensions/titles.py | 4 +- 8 files changed, 113 insertions(+), 100 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 433560eaa..91b871836 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -131,6 +131,8 @@ class LegacyExtension(Extension): def handle_model(self): self.fieldsets = [] + self.filter_horizontal = [] + self.filter_vertical = [] self.list_display = [] self.list_filter = [] self.raw_id_fields = [] @@ -144,6 +146,10 @@ def handle_model(self): def handle_modeladmin(self, modeladmin): if self.fieldsets: modeladmin.fieldsets.extend(self.fieldsets) + if self.filter_horizontal: + modeladmin.filter_horizontal.extend(self.filter_horizontal) + if self.filter_vertical: + modeladmin.filter_vertical.extend(self.filter_vertical) if self.list_display: modeladmin.list_display.extend(self.list_display) if self.list_filter: diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index f2afafdf0..6d9c511ef 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -11,7 +11,7 @@ def register(cls, admin_cls): if hasattr(cls, 'cache_key_components'): cls.cache_key_components.append(lambda page: page.featured) - admin_cls.fieldsets.append((_('Featured'), { + admin_cls.add_extension_options(_('Featured'), { 'fields': ('featured',), 'classes': ('collapse',), - })) + }) diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index 622dcfff9..439cc14be 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -12,10 +12,9 @@ def register(cls, admin_cls): help_text=_('This will be prepended to the default description.'))) if admin_cls: - admin_cls.search_fields += ('meta_keywords', 'meta_description') + admin_cls.search_fields.extend(['meta_keywords', 'meta_description']) - if admin_cls.fieldsets: - admin_cls.fieldsets.append((_('Search engine optimization'), { - 'fields': ('meta_keywords', 'meta_description'), - 'classes': ('collapse',), - })) + admin_cls.add_extension_options(_('Search engine optimization'), { + 'fields': ('meta_keywords', 'meta_description'), + 'classes': ('collapse',), + }) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 044756418..55788564f 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -23,7 +23,7 @@ from django.utils import translation from django.utils.translation import ugettext_lazy as _ -from feincms import settings +from feincms import extensions, settings from feincms.translations import is_primary_language from feincms._internal import monkeypatch_method, monkeypatch_property @@ -115,98 +115,105 @@ def get_current_language_code(request): return language_code # ------------------------------------------------------------------------ -def register(cls, admin_cls): - cls.add_to_class('language', models.CharField(_('language'), max_length=10, - choices=django_settings.LANGUAGES, default=django_settings.LANGUAGES[0][0])) - cls.add_to_class('translation_of', models.ForeignKey('self', - blank=True, null=True, verbose_name=_('translation of'), - related_name='translations', - limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, - help_text=_('Leave this empty for entries in the primary language.') - )) - - if hasattr(cls, 'register_request_processor'): - if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": - cls.register_request_processor(translations_request_processor_explicit, - key='translations') - else: # STANDARD - cls.register_request_processor(translations_request_processor_standard, - key='translations') - - if hasattr(cls, 'get_redirect_to_target'): +class Extension(extensions.Extension): + def handle_model(self): + cls = self.model + + cls.add_to_class('language', models.CharField(_('language'), max_length=10, + choices=django_settings.LANGUAGES, default=django_settings.LANGUAGES[0][0])) + cls.add_to_class('translation_of', models.ForeignKey('self', + blank=True, null=True, verbose_name=_('translation of'), + related_name='translations', + limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, + help_text=_('Leave this empty for entries in the primary language.') + )) + + if hasattr(cls, 'register_request_processor'): + if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": + cls.register_request_processor(translations_request_processor_explicit, + key='translations') + else: # STANDARD + cls.register_request_processor(translations_request_processor_standard, + key='translations') + + if hasattr(cls, 'get_redirect_to_target'): + @monkeypatch_method(cls) + def get_redirect_to_target(self, request): + """ + Find an acceptable redirect target. If this is a local link, then try + to find the page this redirect references and translate it according + to the user's language. This way, one can easily implement a localized + "/"-url to welcome page redirection. + """ + target = self.redirect_to + if target and target.find('//') == -1: # Not an offsite link http://bla/blubb + try: + page = cls.objects.page_for_path(target) + page = page.get_translation(get_current_language_code(request)) + target = page.get_absolute_url() + except cls.DoesNotExist: + pass + return target + @monkeypatch_method(cls) - def get_redirect_to_target(self, request): - """ - Find an acceptable redirect target. If this is a local link, then try - to find the page this redirect references and translate it according - to the user's language. This way, one can easily implement a localized - "/"-url to welcome page redirection. - """ - target = self.redirect_to - if target and target.find('//') == -1: # Not an offsite link http://bla/blubb - try: - page = cls.objects.page_for_path(target) - page = page.get_translation(get_current_language_code(request)) - target = page.get_absolute_url() - except cls.DoesNotExist: - pass - return target - - @monkeypatch_method(cls) - def available_translations(self): - if not self.id: # New, unsaved pages have no translations - return [] - if is_primary_language(self.language): - return self.translations.all() - elif self.translation_of: - return [self.translation_of] + list(self.translation_of.translations.exclude( - language=self.language)) - else: - return [] - - @monkeypatch_method(cls) - def get_original_translation(self, *args, **kwargs): - if is_primary_language(self.language): - return self - return self.translation_of - - @monkeypatch_property(cls) - def original_translation(self): - return self.get_original_translation() - - @monkeypatch_method(cls) - def get_translation(self, language): - return self.original_translation.translations.get(language=language) - - def available_translations_admin(self, page): - translations = dict((p.language, p.id) for p in page.available_translations()) - - links = [] - - for key, title in django_settings.LANGUAGES: - if key == page.language: - continue - - if key in translations: - links.append(u'<a href="%s/" title="%s">%s</a>' % ( - translations[key], _('Edit translation'), key.upper())) + def available_translations(self): + if not self.id: # New, unsaved pages have no translations + return [] + if is_primary_language(self.language): + return self.translations.all() + elif self.translation_of: + return [self.translation_of] + list(self.translation_of.translations.exclude( + language=self.language)) else: - links.append(u'<a style="color:#baa" href="add/?translation_of=%s&language=%s" title="%s">%s</a>' % ( - page.id, key, _('Create translation'), key.upper())) + return [] + + @monkeypatch_method(cls) + def get_original_translation(self, *args, **kwargs): + if is_primary_language(self.language): + return self + return self.translation_of + + @monkeypatch_property(cls) + def original_translation(self): + return self.get_original_translation() + + @monkeypatch_method(cls) + def get_translation(self, language): + return self.original_translation.translations.get(language=language) - return u' | '.join(links) + def handle_modeladmin(self, modeladmin): - available_translations_admin.allow_tags = True - available_translations_admin.short_description = _('translations') - admin_cls.available_translations_admin = available_translations_admin + def available_translations_admin(self, page): + translations = dict((p.language, p.id) for p in page.available_translations()) - if hasattr(admin_cls, 'add_extension_options'): - admin_cls.add_extension_options('language', 'translation_of') + links = [] - admin_cls.list_display.extend(['language', 'available_translations_admin']) - admin_cls.list_filter.extend(['language']) + for key, title in django_settings.LANGUAGES: + if key == page.language: + continue - admin_cls.raw_id_fields.append('translation_of') + if key in translations: + links.append(u'<a href="%s/" title="%s">%s</a>' % ( + translations[key], _('Edit translation'), key.upper())) + else: + links.append(u'<a style="color:#baa" href="add/?translation_of=%s&language=%s" title="%s">%s</a>' % ( + page.id, key, _('Create translation'), key.upper())) + + return u' | '.join(links) + + available_translations_admin.allow_tags = True + available_translations_admin.short_description = _('translations') + modeladmin.__class__.available_translations_admin = available_translations_admin + + if hasattr(modeladmin, 'add_extension_options'): + modeladmin.add_extension_options('language', 'translation_of') + + modeladmin.list_display.extend(['language', 'available_translations_admin']) + modeladmin.list_filter.extend(['language']) + + modeladmin.raw_id_fields.append('translation_of') # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ + +register = Extension diff --git a/feincms/module/page/extensions/excerpt.py b/feincms/module/page/extensions/excerpt.py index b13aa174b..be987ffd4 100644 --- a/feincms/module/page/extensions/excerpt.py +++ b/feincms/module/page/extensions/excerpt.py @@ -9,7 +9,7 @@ def register(cls, admin_cls): cls.add_to_class('excerpt', models.TextField(_('excerpt'), blank=True, help_text=_('Add a brief excerpt summarizing the content of this page.'))) - admin_cls.fieldsets.append((_('Excerpt'), { + admin_cls.add_extension_options(_('Excerpt'), { 'fields': ('excerpt',), 'classes': ('collapse',), - })) + }) diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 9a9146a8c..db0f26748 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -17,7 +17,7 @@ def register(cls, admin_cls): except AttributeError: admin_cls.filter_horizontal = ['related_pages'] - admin_cls.fieldsets.append((_('Related pages'), { + admin_cls.add_extension_options(_('Related pages'), { 'fields': ('related_pages',), 'classes': ('collapse',), - })) + }) diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index 706445475..befa7e1de 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -19,3 +19,4 @@ def register(cls, admin_cls): PageManager.add_to_active_filters(current_site, key='current_site') admin_cls.list_display.extend(['site']) + admin_cls.list_filter.extend(['site']) diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index 10121baf8..ac19bb2c0 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -40,7 +40,7 @@ def content_title(self): def content_subtitle(self): return u'\n'.join(self._content_title.splitlines()[1:]) - admin_cls.fieldsets.append((_('Titles'), { + admin_cls.add_extension_options(_('Titles'), { 'fields': ('_content_title', '_page_title'), 'classes': ('collapse',), - })) + }) From 5a5e7f26044ae1da3ba3f0046808e3f92b68edef Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 14:35:30 +0200 Subject: [PATCH 0436/1590] add_extension_options: Stop early if self.fieldsets is None --- feincms/extensions.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 91b871836..ca0f0c928 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -184,9 +184,12 @@ def initialize_extensions(self): extension.handle_modeladmin(self) def add_extension_options(self, *f): + if self.fieldsets is None: + return + if isinstance(f[-1], dict): # called with a fieldset self.fieldsets.insert(self.fieldset_insertion_index, f) f[1]['classes'] = list(f[1].get('classes', [])) f[1]['classes'].append('collapse') - elif f and self.fieldsets: # assume called with "other" fields + elif f: # assume called with "other" fields self.fieldsets[1][1]['fields'].extend(f) From 6126d9e2ad6ed01c26d7f3c029f231ab19765685 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 15:10:20 +0200 Subject: [PATCH 0437/1590] Remove get/post/handler from ContentView This only belongs on subclasses. --- feincms/module/mixins.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 860d5f697..9c1c0f538 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -51,16 +51,6 @@ class ContentView(TemplateView): #: The name of the object for the template rendering context context_object_name = 'feincms_object' - def get(self, request, *args, **kwargs): - return self.handler(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - return self.handler(request, *args, **kwargs) - - def handler(self, request, *args, **kwargs): - self.page = Page.objects.for_request(request, - raise404=True, best_match=True) - def handle_object(self, object): if not hasattr(self.request, '_feincms_extra_context'): self.request._feincms_extra_context = {} From 15c9805415f479f9f59c57871f22df100025ea80 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 15:12:49 +0200 Subject: [PATCH 0438/1590] Move _feincms_extra_context handling into handle object It has nothing to do with request processors. Thanks to Marc Tamlyn for pointing this out. --- feincms/module/mixins.py | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 9c1c0f538..7ccd50fc8 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -52,10 +52,24 @@ class ContentView(TemplateView): context_object_name = 'feincms_object' def handle_object(self, object): + self.object = object + if not hasattr(self.request, '_feincms_extra_context'): self.request._feincms_extra_context = {} - self.object = object + self.request._feincms_extra_context.update({ + # XXX This variable name isn't accurate anymore. + 'in_appcontent_subpage': False, + 'extra_path': '/', + }) + + url = self.object.get_absolute_url() + if self.request.path != url: + self.request._feincms_extra_context.update({ + 'in_appcontent_subpage': True, + 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', + self.request.path), + }) r = self.run_request_processors() if r: @@ -110,24 +124,6 @@ def run_request_processors(self): also return a ``HttpResponse`` for shortcutting the rendering and returning that response immediately to the client. """ - - self.request._feincms_extra_context.update({ - # XXX This variable name isn't accurate anymore. - # We _are_ in a subpage, but it isn't necessarily - # an appcontent subpage. - 'in_appcontent_subpage': False, - 'extra_path': '/', - }) - - url = self.object.get_absolute_url() - if self.request.path != url: - # extra_path must not end with a slash - self.request._feincms_extra_context.update({ - 'in_appcontent_subpage': True, - 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', - self.request.path), - }) - for fn in reversed(self.object.request_processors.values()): r = fn(self.object, self.request) if r: From f92609106c2f84dd96f621ee0cc2d13cdafebe12 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 15:14:38 +0200 Subject: [PATCH 0439/1590] Do not simply crash when templates are missing in ContentView Raise an exception pointing out the problem instead. Thanks to Marc Tamlyn for the suggestion. --- feincms/module/mixins.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 7ccd50fc8..620d9dcfe 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -100,8 +100,7 @@ def get_template_names(self): if self.template_name: return [self.template_name] - # Hopefully someone run register_templates on the object class - # beforehand, otherwise we'll crash... + self.object._needs_templates() return [self.object.template.path] def get_context_data(self, **kwargs): From dda9366110b3d4de4753f3511170a1e9e78bc002 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 15:35:41 +0200 Subject: [PATCH 0440/1590] Quick fix for extension problem --- feincms/module/page/extensions/navigation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 5d4a6feb3..3304cdd34 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -119,3 +119,5 @@ def handle_modeladmin(self, modeladmin): 'fields': ('navigation_extension',), 'classes': ('collapse',), }) + +register = Extension From 1abb72dd8b5ce3f16aca306e9f76d89cfc715239 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 15:35:25 +0200 Subject: [PATCH 0441/1590] Ensure that request and response processors are not shared --- feincms/module/mixins.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 620d9dcfe..de2d8a121 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -17,10 +17,10 @@ class ContentMixin(object): """ #: Collection of request processors - request_processors = SortedDict() + request_processors = None #: Collection of response processors - response_processors = SortedDict() + response_processors = None def setup_request(self, request): import warnings @@ -35,6 +35,8 @@ def register_request_processor(cls, fn, key=None): Registers the passed callable as request processor. A request processor always receives two arguments, the current object and the request. """ + if cls.request_processors is None: + cls.request_processors = SortedDict() cls.request_processors[fn if key is None else key] = fn @classmethod @@ -44,6 +46,8 @@ def register_response_processor(cls, fn, key=None): processor always receives three arguments, the current object, the request and the response. """ + if cls.response_processors is None: + cls.response_processors = SortedDict() cls.response_processors[fn if key is None else key] = fn @@ -123,6 +127,9 @@ def run_request_processors(self): also return a ``HttpResponse`` for shortcutting the rendering and returning that response immediately to the client. """ + if self.object.request_processors is None: + return + for fn in reversed(self.object.request_processors.values()): r = fn(self.object, self.request) if r: @@ -134,6 +141,9 @@ def run_response_processors(self, response): processors are called to modify the response, eg. for setting cache or expiration headers, keeping statistics, etc. """ + if self.object.response_processors is None: + return + for fn in self.object.response_processors.values(): r = fn(self.object, self.request, response) if r: From 19f50f9a58983b1bb02d349c3bd78b2bf223de4b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 16:02:06 +0200 Subject: [PATCH 0442/1590] get_object: Try importing the path as module first Otherwise, importing modules fails under certain Python versions. --- feincms/module/extensions/translations.py | 2 -- feincms/module/page/extensions/navigation.py | 2 -- feincms/utils/__init__.py | 17 ++++++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 55788564f..18466eb6a 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -215,5 +215,3 @@ def available_translations_admin(self, page): # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ - -register = Extension diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 3304cdd34..5d4a6feb3 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -119,5 +119,3 @@ def handle_modeladmin(self, modeladmin): 'fields': ('navigation_extension',), 'classes': ('collapse',), }) - -register = Extension diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 9b08c65d7..562d7bc4f 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -18,14 +18,17 @@ def get_object(path, fail_silently=False): if not isinstance(path, (str, unicode)): return path - dot = path.rindex('.') - mod, fn = path[:dot], path[dot+1:] - try: - return getattr(import_module(mod), fn) - except (AttributeError, ImportError): - if not fail_silently: - raise + return import_module(path) + except ImportError: + try: + dot = path.rindex('.') + mod, fn = path[:dot], path[dot+1:] + + return getattr(import_module(mod), fn) + except (AttributeError, ImportError): + if not fail_silently: + raise # ------------------------------------------------------------------------ def collect_dict_values(data): From a547b093f6fdd6832ba2f769122a3b34e2d6c717 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 16:27:33 +0200 Subject: [PATCH 0443/1590] Convert manage.py to Django 1.4 style --- example/manage.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/example/manage.py b/example/manage.py index 191a59a72..2a3cb9b1d 100755 --- a/example/manage.py +++ b/example/manage.py @@ -1,14 +1,11 @@ #!/usr/bin/env python -import sys -sys.path.insert(0, '..') - -from django.core.management import execute_manager -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) - sys.exit(1) - -if __name__ == "__main__": - execute_manager(settings) +import os, sys + +sys.path.insert(0, + os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings') + +from django.core.management import execute_from_command_line + +execute_from_command_line(sys.argv) From 918a9b0d176e8e6663be56890c0b192a8d87f7bc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 17:00:09 +0200 Subject: [PATCH 0444/1590] Allow putting all content on a secondary database Refs #243. --- feincms/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index f2aaf9a60..8e5175461 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -10,7 +10,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured -from django.db import connection, models +from django.db import connections, models from django.db.models import Q from django.db.models.fields import FieldDoesNotExist from django.db.models.loading import get_model @@ -93,6 +93,7 @@ class ContentProxy(object): def __init__(self, item): item._needs_content_types() self.item = item + self.db = item._state.db self._cache = { 'cts': {}, } @@ -167,7 +168,7 @@ def _fetch_content_type_count_helper(self, pk, regions=None): for idx, cls in enumerate(self.item._feincms_content_types)]) sql = 'SELECT * FROM ( ' + sql + ' ) AS ct ORDER BY ct_idx' - cursor = connection.cursor() + cursor = connections[self.db].cursor() cursor.execute(sql, args) _c = {} From 9e8afe38366a3e354102f79f9c318a02c8e19295 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 17:55:08 +0200 Subject: [PATCH 0445/1590] Update the example DB --- example/example.db | Bin 96256 -> 96256 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/example/example.db b/example/example.db index c9e79d5a36cf234032d27ca3ed77b4bf9d97cbfc..b4f1b46a486c43a9b2d7f4e831fba4117e864dbd 100644 GIT binary patch delta 1289 zcmYLIYfMx}6rOX=-CfyUWI<qAL0AdMV+B^+q9_m7AX<E3wb+KJfGm;*S_|76qc&Jd zOd5YcPV1$zyU<`CsZDFRE!YM%HpEbC)7GSfQd?TmDnG<xg3w5-ods?0%=cyPH}lQR znKRQgX=s`>w8n=2Eri%B@%XD~TfS0?8Dj|sDOu=Tu%o=~U_8<}JzPx&{WF+_NGU#7 zEUDBj$!?RhF`ox$-2$X(`6CK+RT(Ffp-8q<o%*cFXb+_>5e2&i{YKa5bGD=|L&)h4 zS3!{-OZ7ErHK@qZHa_FnW21{A3LS!;r=RIIeT%dBJ>H^su%F|X$0&4+j>*l8O6x@t zt=lr+g`hQD|1zu4X`}O^5WRx#(-hsIaT=o=G(_LgRkl~uhg9LCqPJFD2a6mWVcj5E zwH8S>>J3%JV3CtWD5_*tc|x*LAKahovSE>k7A1m)=|eh7dua_t<9!^)UbZW-R3b|B z)rvY7L<4U!CIz=t!UyLYiF*6#I&fJ<gOIgdTohxVLJm9)UN{Ap;0`Xq^;nPX*o!0h zfKsT8TI4!Eh;41|Xx`>a;*ri}{Ha81XA;+RrgNTzy)%v<1QPj1AQ4j%d8<E$zX^o# z>wzqOM#33LW<$WiBYp?>`{TLYpTu5?&Hglw^JnpdFN+6#$?W$zxWVV>=`zNdodSOp zPCNp?a=2;_YtC3^vaVeVEiZX1tLi-b&#+a$e!&IWD`il|o=Y8^+rNc(UW(9L`ct5% z2^1UrB9?+vfD<;r9(WmApdHS_7jTX315QO|WL)1i&<YNDK6#*2R#)$<_cS(E9`Kl@ z5(Ucs+R7IWcpi(v1Vrf}S7w2hKo*+@*D7K{OmOkw`@s`l&vyqG#ma^QtdERdPouZ~ z#cEGok(49#gs;XHhhm37aYBd_&;SiGu*3R^-y?&$0*~H#(-WE=A&v@JyTny71&L4w zZ@|YejEHGihRt}H4D=MeMwi7F>0S!ExO6IwH~Ug}XeJ#~S8~^M3}2bC@T)VKTr%V0 z=ouF#uHsT(6o<@&^5Aqj2P6(nr*O%11}~8qy;r~;_lkJ8MEt#69-S)WuBpPFzZ6wP zJT34vJsB)*?zq0?3Yg|D`6rrFfwRGrI&Up^!|`%0-vIVL)d&wm4dqfUmoMW_;)jb2 z7Nba&&kr<Qh;LB{HMO}T`#y+)XGy!A2Ti?kV6>Ze2(d$ajhXm|X2}D0UtK=DiG8Q4 zAQpPp$pH&%g{T#MkPSoFD28P4yR^6SV7nGu1xK_)m2gHIsQ`aiv$@!0b-SS@VeX!2 zcMY(Z2W~d<@SRev)&>z=a3Pxa-AdCY3&2I*!v}f$PgXRi^;UzTEI{lQREphl^BS6u zr*AS@cgpCt&PBH%XJyTbRh27p=4REhjgbDo^pOHt=HnR~=M6jO4OKa-T&uI4x$}l5 TgEagnNkfu$(g+LRs{{34JRN** delta 1232 zcmYjPe@t6d6u#%4``TF^LWNSG{CFZzN(U4Hmkk`S!ElI(CbH?Wtpz%W;m2f{1*e9w zA)1(Fc+9#;TTnM$=91x_gJ=+)Sxje0j4oM}s3<YhKbQeiKtnRU1*g8`JNfSS?mhRM z@1DK|rEftwX)}izWBVlTd`}H+ERtg0+`WpFV(@b0$CE<`({!_H2mLavLVQMZSBqE5 z4HYtINix)w(N(P2fVe0ZY>%#rU(vX=O7fgSebs2tVkEV~0}Ow{Y5WjJ>F%8Dx6LYu zbgRPjEsg_RScSsqjB{^EWGlBYd>X&UDV)bI`6~a4|AKGwNp8VixQ)NeJ9rIuqKUtS z#i-${_<}5N7KBCE()FbLvmj!H#ioB&Q0_9wbk)3xjP1`*x7&i9yiGsp{u*ekQ>fNz z1p%y8k*Ie!?SR+_6Y5%wT2n*Kn~TjdM-r=L_zj-N=W!oy(eDwnNQ=X9#fhw*;S7F& zC-DH5p~i3X@3_v7^C!5AD=-6-a2k5xVMt-OScnB!H>)42OrUyyCU>}~D`=tlk$5^k z;-rC*ENUDnAiKovpo3<DnKUkOI+#WsK__jKNDXGuZ-D~(Bv8QZ8Ly2b(pVsddIA~r zcp$@;oUX7eNZsz~)I2RM+CfjNH%gNIl2BB@Npt>On)1tx{%q>@XI~mMq?iU68-NRF zL@$|D2OXKJ)4!dvgQ<Uaw$WNz3dd{oEt3sE&rR*8A3q)*-vC0SWP*!<3#wr+JPQM| z!}s7Ln1&x<fh&}J)ulIFJpoR$fcrp13h3}2IwXrR#S3tNXm0a#wtDY~Q4vwU>+@AW zjol(+s8oOr1nmgDD-s0c(PAjh79n8$=U|WbP)~=P!S<>+0d_t8+FWw9d?I9nj1RLx z=$4)I>VrSWbJ5?FZ`4O_dZTmWSRKO~cmZF;T1?=-^AHd6!@QQK!YmBKE=XguY?Sq~ zI(a%xIIHA1HiRAatnCUb1p6INBX?_Sms=x^{aXrMSt+M}iJdE(Nm;3)E6Y`MY<Vj+ zF6WU$f-l>7&SshpCmQ2q>E0eMon0#88JnoVZ;6hJBy0Bccw4)=d#Q1$m@*{7;e7fc zoJ*tO+)IB5RTWUgpa|yp8(1<_nKH3afDwE$UNjvoDKT32RKn3cz6TZ1CR79b6|G0b z{)w>)JIB~LZsjM?g0HZgp~`q)pAGsZauQ)Tj;DY@GtDzL5AARhclu(>pprE8Azzyt z9u?A8vA+AUGI*VzlFvUODu8S14CANpeQtxpY(`oZ^4;)2z<0j~&iE$WaKzM~Sh+Sp z$7+0^x*@?g<_3c=svMRKk8CqoJ*9L}OZ2_uhQjd{IZ_6|>kO~!X7w88Ija@63GyPI SuUn=4&-QiYKj+_R2la2^P;09I From ae45c3890a9c7a96710575aca4571355ac1a367a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 17:55:08 +0200 Subject: [PATCH 0446/1590] Update the example DB --- example/example.db | Bin 96256 -> 96256 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/example/example.db b/example/example.db index c9e79d5a36cf234032d27ca3ed77b4bf9d97cbfc..b4f1b46a486c43a9b2d7f4e831fba4117e864dbd 100644 GIT binary patch delta 1289 zcmYLIYfMx}6rOX=-CfyUWI<qAL0AdMV+B^+q9_m7AX<E3wb+KJfGm;*S_|76qc&Jd zOd5YcPV1$zyU<`CsZDFRE!YM%HpEbC)7GSfQd?TmDnG<xg3w5-ods?0%=cyPH}lQR znKRQgX=s`>w8n=2Eri%B@%XD~TfS0?8Dj|sDOu=Tu%o=~U_8<}JzPx&{WF+_NGU#7 zEUDBj$!?RhF`ox$-2$X(`6CK+RT(Ffp-8q<o%*cFXb+_>5e2&i{YKa5bGD=|L&)h4 zS3!{-OZ7ErHK@qZHa_FnW21{A3LS!;r=RIIeT%dBJ>H^su%F|X$0&4+j>*l8O6x@t zt=lr+g`hQD|1zu4X`}O^5WRx#(-hsIaT=o=G(_LgRkl~uhg9LCqPJFD2a6mWVcj5E zwH8S>>J3%JV3CtWD5_*tc|x*LAKahovSE>k7A1m)=|eh7dua_t<9!^)UbZW-R3b|B z)rvY7L<4U!CIz=t!UyLYiF*6#I&fJ<gOIgdTohxVLJm9)UN{Ap;0`Xq^;nPX*o!0h zfKsT8TI4!Eh;41|Xx`>a;*ri}{Ha81XA;+RrgNTzy)%v<1QPj1AQ4j%d8<E$zX^o# z>wzqOM#33LW<$WiBYp?>`{TLYpTu5?&Hglw^JnpdFN+6#$?W$zxWVV>=`zNdodSOp zPCNp?a=2;_YtC3^vaVeVEiZX1tLi-b&#+a$e!&IWD`il|o=Y8^+rNc(UW(9L`ct5% z2^1UrB9?+vfD<;r9(WmApdHS_7jTX315QO|WL)1i&<YNDK6#*2R#)$<_cS(E9`Kl@ z5(Ucs+R7IWcpi(v1Vrf}S7w2hKo*+@*D7K{OmOkw`@s`l&vyqG#ma^QtdERdPouZ~ z#cEGok(49#gs;XHhhm37aYBd_&;SiGu*3R^-y?&$0*~H#(-WE=A&v@JyTny71&L4w zZ@|YejEHGihRt}H4D=MeMwi7F>0S!ExO6IwH~Ug}XeJ#~S8~^M3}2bC@T)VKTr%V0 z=ouF#uHsT(6o<@&^5Aqj2P6(nr*O%11}~8qy;r~;_lkJ8MEt#69-S)WuBpPFzZ6wP zJT34vJsB)*?zq0?3Yg|D`6rrFfwRGrI&Up^!|`%0-vIVL)d&wm4dqfUmoMW_;)jb2 z7Nba&&kr<Qh;LB{HMO}T`#y+)XGy!A2Ti?kV6>Ze2(d$ajhXm|X2}D0UtK=DiG8Q4 zAQpPp$pH&%g{T#MkPSoFD28P4yR^6SV7nGu1xK_)m2gHIsQ`aiv$@!0b-SS@VeX!2 zcMY(Z2W~d<@SRev)&>z=a3Pxa-AdCY3&2I*!v}f$PgXRi^;UzTEI{lQREphl^BS6u zr*AS@cgpCt&PBH%XJyTbRh27p=4REhjgbDo^pOHt=HnR~=M6jO4OKa-T&uI4x$}l5 TgEagnNkfu$(g+LRs{{34JRN** delta 1232 zcmYjPe@t6d6u#%4``TF^LWNSG{CFZzN(U4Hmkk`S!ElI(CbH?Wtpz%W;m2f{1*e9w zA)1(Fc+9#;TTnM$=91x_gJ=+)Sxje0j4oM}s3<YhKbQeiKtnRU1*g8`JNfSS?mhRM z@1DK|rEftwX)}izWBVlTd`}H+ERtg0+`WpFV(@b0$CE<`({!_H2mLavLVQMZSBqE5 z4HYtINix)w(N(P2fVe0ZY>%#rU(vX=O7fgSebs2tVkEV~0}Ow{Y5WjJ>F%8Dx6LYu zbgRPjEsg_RScSsqjB{^EWGlBYd>X&UDV)bI`6~a4|AKGwNp8VixQ)NeJ9rIuqKUtS z#i-${_<}5N7KBCE()FbLvmj!H#ioB&Q0_9wbk)3xjP1`*x7&i9yiGsp{u*ekQ>fNz z1p%y8k*Ie!?SR+_6Y5%wT2n*Kn~TjdM-r=L_zj-N=W!oy(eDwnNQ=X9#fhw*;S7F& zC-DH5p~i3X@3_v7^C!5AD=-6-a2k5xVMt-OScnB!H>)42OrUyyCU>}~D`=tlk$5^k z;-rC*ENUDnAiKovpo3<DnKUkOI+#WsK__jKNDXGuZ-D~(Bv8QZ8Ly2b(pVsddIA~r zcp$@;oUX7eNZsz~)I2RM+CfjNH%gNIl2BB@Npt>On)1tx{%q>@XI~mMq?iU68-NRF zL@$|D2OXKJ)4!dvgQ<Uaw$WNz3dd{oEt3sE&rR*8A3q)*-vC0SWP*!<3#wr+JPQM| z!}s7Ln1&x<fh&}J)ulIFJpoR$fcrp13h3}2IwXrR#S3tNXm0a#wtDY~Q4vwU>+@AW zjol(+s8oOr1nmgDD-s0c(PAjh79n8$=U|WbP)~=P!S<>+0d_t8+FWw9d?I9nj1RLx z=$4)I>VrSWbJ5?FZ`4O_dZTmWSRKO~cmZF;T1?=-^AHd6!@QQK!YmBKE=XguY?Sq~ zI(a%xIIHA1HiRAatnCUb1p6INBX?_Sms=x^{aXrMSt+M}iJdE(Nm;3)E6Y`MY<Vj+ zF6WU$f-l>7&SshpCmQ2q>E0eMon0#88JnoVZ;6hJBy0Bccw4)=d#Q1$m@*{7;e7fc zoJ*tO+)IB5RTWUgpa|yp8(1<_nKH3afDwE$UNjvoDKT32RKn3cz6TZ1CR79b6|G0b z{)w>)JIB~LZsjM?g0HZgp~`q)pAGsZauQ)Tj;DY@GtDzL5AARhclu(>pprE8Azzyt z9u?A8vA+AUGI*VzlFvUODu8S14CANpeQtxpY(`oZ^4;)2z<0j~&iE$WaKzM~Sh+Sp z$7+0^x*@?g<_3c=svMRKk8CqoJ*9L}OZ2_uhQjd{IZ_6|>kO~!X7w88Ija@63GyPI SuUn=4&-QiYKj+_R2la2^P;09I From 0a5bbe5b7b50091d67028781ca6d64ed591e89b1 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn <marc.tamlyn@gmail.com> Date: Mon, 18 Jun 2012 19:31:21 +0100 Subject: [PATCH 0447/1590] Improve the ContentView. View is now cleaner and handles objects in a more standard way (coming from DetailView rather than TemplateView). There are no get/post methods, just all http methods dispatched straight to the handler. One test failing (but it was before anyway). Something to do with messages. --- feincms/contrib/preview/views.py | 16 ++++++++++------ feincms/module/mixins.py | 17 ++++++++++++----- feincms/views/cbv/views.py | 30 +++++++----------------------- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 2c0fa8a4a..6ac8d49e1 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -14,17 +14,21 @@ class PreviewHandler(Handler): *** Everything here is subject to change. *** """ - def handler(self, request, path, page_id): - if not request.user.is_staff: - raise Http404() + def get_object(self): + """Get the page by the id in the url here instead.""" - page = get_object_or_404(Page, pk=page_id) + page = get_object_or_404(Page, pk=self.args[1]) # Remove _preview/42/ from URL, the rest of the handler code should not # know that anything about previewing. Handler.prepare will still raise # a 404 if the extra_path isn't consumed by any content type - request.path = page.get_absolute_url() + self.request.path = page.get_absolute_url() + + return page - response = self.handle_object(page) + def handler(self, request, *args, **kwargs): + if not request.user.is_staff: + raise Http404() + response = super(PreviewHandler, self).handler(request, *args, **kwargs) response['Cache-Control'] = 'no-cache, must-revalidate, no-store, private' return response diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index de2d8a121..c389dcf53 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -1,11 +1,10 @@ import re -from django.db import models from django.http import Http404 from django.template import Template from django.utils.cache import add_never_cache_headers from django.utils.datastructures import SortedDict -from django.views.generic import TemplateView +from django.views.generic import DetailView from feincms import settings @@ -51,12 +50,20 @@ def register_response_processor(cls, fn, key=None): cls.response_processors[fn if key is None else key] = fn -class ContentView(TemplateView): +class ContentView(DetailView): #: The name of the object for the template rendering context context_object_name = 'feincms_object' - def handle_object(self, object): - self.object = object + def dispatch(self, request, *args, **kwargs): + if request.method.lower() not in self.http_method_names: + return self.http_method_not_allowed(request, *args, **kwargs) + self.request = request + self.args = args + self.kwargs = kwargs + self.object = self.get_object() + return self.handler(request, *args, **kwargs) + + def handler(self, request, *args, **kwargs): if not hasattr(self.request, '_feincms_extra_context'): self.request._feincms_extra_context = {} diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 0c6e51306..7e8f1680c 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -5,42 +5,26 @@ from feincms.module.page.models import Page -class HandlerBase(ContentView): - """ - Class-based handler for FeinCMS page content - """ +class Handler(ContentView): context_object_name = 'feincms_page' - def get(self, request, *args, **kwargs): - return self.handler(request, *args, **kwargs) + def get_object(self): + return Page.objects.for_request(self.request, raise404=True, + best_match=True, setup=False) - def post(self, request, *args, **kwargs): - return self.handler(request, *args, **kwargs) - - def handler(self, request, *args, **kwargs): - page = Page.objects.for_request(request, - raise404=True, best_match=True, setup=False) - - return self.handle_object(page) - - -# ------------------------------------------------------------------------ -class Handler(HandlerBase): - def handler(self, request, *args, **kwargs): + def dispatch(self, request, *args, **kwargs): try: - return super(Handler, self).handler(request, *args, **kwargs) + return super(Handler, self).dispatch(request, *args, **kwargs) except Http404, e: if settings.FEINCMS_CMS_404_PAGE: try: request.original_path_info = request.path_info request.path_info = settings.FEINCMS_CMS_404_PAGE - response = super(Handler, self).handler(request, *args, **kwargs) + response = super(Handler, self).dispatch(request, *args, **kwargs) response.status_code = 404 return response except Http404: raise e else: raise - -# ------------------------------------------------------------------------ From b7a3a2b5c8b0de7618c4e5bdce60017101c0f000 Mon Sep 17 00:00:00 2001 From: Maarten Draijer <maarten@madra.nl> Date: Mon, 18 Jun 2012 21:00:26 +0200 Subject: [PATCH 0448/1590] Static files should be loaded via STATIC_URL. --- docs/page.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/page.rst b/docs/page.rst index bd15f5a47..f0ecd67f9 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -78,7 +78,7 @@ need to download `TinyMCE <http://www.tinymce.com/>`_ and configure FeinCMS' richtext support:: FEINCMS_RICHTEXT_INIT_CONTEXT = { - 'TINYMCE_JS_URL': MEDIA_URL + 'your_custom_path/tiny_mce.js', + 'TINYMCE_JS_URL': STATIC_URL + 'your_custom_path/tiny_mce.js', } @@ -312,7 +312,7 @@ init_richtext.html that inherits from `admin/content/richtext/init_tinymce.html` You can even set your own css and linklist files like so:: FEINCMS_RICHTEXT_INIT_CONTEXT = { - 'TINYMCE_JS_URL': MEDIA_URL + 'your_custom_path/tiny_mce.js', + 'TINYMCE_JS_URL': STATIC_URL + 'your_custom_path/tiny_mce.js', 'TINYMCE_CONTENT_CSS_URL': None, # add your css path here 'TINYMCE_LINK_LIST_URL': None # add your linklist.js path here } @@ -322,7 +322,7 @@ that one. Change the following settings:: FEINCMS_RICHTEXT_INIT_TEMPLATE = 'admin/content/richtext/init_ckeditor.html' FEINCMS_RICHTEXT_INIT_CONTEXT = { - 'CKEDITOR_JS_URL': MEDIA_URL + 'path_to_your/ckeditor.js') + 'CKEDITOR_JS_URL': STATIC_URL + 'path_to_your/ckeditor.js') } .. _TinyMCE: http://www.tinymce.com/ From 951b8e6458ea8ef8eb3fd97e97380b03a0e118ba Mon Sep 17 00:00:00 2001 From: Maarten Draijer <maarten@madra.nl> Date: Mon, 18 Jun 2012 21:01:00 +0200 Subject: [PATCH 0449/1590] Fix a little typo within the documentation. --- docs/page.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/page.rst b/docs/page.rst index f0ecd67f9..4bd580bf4 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -322,7 +322,7 @@ that one. Change the following settings:: FEINCMS_RICHTEXT_INIT_TEMPLATE = 'admin/content/richtext/init_ckeditor.html' FEINCMS_RICHTEXT_INIT_CONTEXT = { - 'CKEDITOR_JS_URL': STATIC_URL + 'path_to_your/ckeditor.js') + 'CKEDITOR_JS_URL': STATIC_URL + 'path_to_your/ckeditor.js', } .. _TinyMCE: http://www.tinymce.com/ From de348f7d104e9b44a62a673e1740de507ba69fa7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 22:00:41 +0200 Subject: [PATCH 0450/1590] Do it right --- example/example.db | Bin 96256 -> 96256 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/example/example.db b/example/example.db index b4f1b46a486c43a9b2d7f4e831fba4117e864dbd..0a058a1953d7907a7f66d00682ecccd639754323 100644 GIT binary patch delta 421 zcmZqpz}oPEb%K--69W*$fe0u_nW$p~64iYq&k7V0VBP?dh}>A<%q$S#24uQB0tp34 zAmP@0n0fnQW=30qWfF`m0=z&W7KT6uAUe&Y$Mkf%fCQuC_COoP^~~F37+DkqSQ%0n zfM_$L9^)mZe1@5m1$k_z1LcL;e4W_D6Rjt&SCH7=mcaOqk(1AjUEI-;u~mI~Z4%?8 z$yskTCdWV5oW3EM(PZ-O=W^5M+cNS_w@PMIn;sFyD7XE;JtM0E9~0AJ2IgR<#Y~eJ zzcQo%O%LK~Ce5JfR}&fMNjECGu#5XzGd8+s=B1=oq*gTQda#QJJ2Ex~Pq$@dRG40s z&8Wl}J-v~YQFHpSY(^{QMlJX0%d!|fr#G-NYE3_z#mF&TF`H3;8V4iGc9s;zKg=Rr lz`y~94hVn((G`eoHw*IgGfiKd#kdwEy8+3D?LZsacmRf4Y^eYM delta 265 zcmZqpz}oPEb%K--;~xeFhBzRGfrN=VMj%n$NAj#dF#+ZcAercm1<uR@k#0a{fFqDl zkOUI$&4-z{A7*B>6__Nz%^D3-wpozpJ@fYe!i<b8+hiD76a-ip0vUklG?O0FQ-+xg zGbc{8-5w~xxSn~N14x>cA%g*kwlf+rUSld|xHfTO2%E1Hn|Px2<n;;?+na0{-!XD> zxv`5oIx@D(PtQwWoHY5yyMXC0L>Psp%i1#*GnZ5rO!mJm&d9a>e=^Wk9$ug`n3xtb sFb6O#2D)ZC)AYqzjBA-2b={{gOJek#-oVPJHT`T7Bggi0*^EX!0C>+t$^ZZW From 3817da84f90ed774d57406f572043eb639d005cb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 22:14:19 +0200 Subject: [PATCH 0451/1590] Move feincms_extra_context handling into request processor --- feincms/module/mixins.py | 19 +------------------ feincms/module/page/models.py | 2 ++ feincms/module/page/processors.py | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index c389dcf53..aabb6b5a6 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -1,5 +1,3 @@ -import re - from django.http import Http404 from django.template import Template from django.utils.cache import add_never_cache_headers @@ -64,24 +62,9 @@ def dispatch(self, request, *args, **kwargs): return self.handler(request, *args, **kwargs) def handler(self, request, *args, **kwargs): - if not hasattr(self.request, '_feincms_extra_context'): self.request._feincms_extra_context = {} - self.request._feincms_extra_context.update({ - # XXX This variable name isn't accurate anymore. - 'in_appcontent_subpage': False, - 'extra_path': '/', - }) - - url = self.object.get_absolute_url() - if self.request.path != url: - self.request._feincms_extra_context.update({ - 'in_appcontent_subpage': True, - 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', - self.request.path), - }) - r = self.run_request_processors() if r: return r @@ -184,7 +167,7 @@ def process_content_types(self): raise http404 if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ - self.request._feincms_extra_context['extra_path'] != '/': + self.request._feincms_extra_context.get('extra_path', '/') != '/': raise Http404() def finalize_content_types(self, response): diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 223541bcf..7dade059e 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -331,6 +331,8 @@ def path_to_cache_key(path): # ------------------------------------------------------------------------ # Our default request processors +Page.register_request_processor(processors.extra_context_request_processor, + key='extra_context') Page.register_request_processor(processors.redirect_request_processor, key='redirect') diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 3a5efb4a3..d9f0e09e0 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -1,3 +1,4 @@ +import re import sys from django.conf import settings as django_settings @@ -16,6 +17,25 @@ def redirect_request_processor(page, request): raise Http404() +def extra_context_request_processor(page, request): + """ + Fills ``request._feincms_extra_context`` with a few useful variables. + """ + request._feincms_extra_context.update({ + # XXX This variable name isn't accurate anymore. + 'in_appcontent_subpage': False, + 'extra_path': '/', + }) + + url = object.get_absolute_url() + if request.path != url: + request._feincms_extra_context.update({ + 'in_appcontent_subpage': True, + 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', + request.path), + }) + + def frontendediting_request_processor(page, request): """ Sets the frontend editing state in the session depending on the From ff8fafecc40eaaaa40de1ff1fab5b4bde82b1428 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 22:17:44 +0200 Subject: [PATCH 0452/1590] Move frontend editing cache control into response processor --- feincms/module/mixins.py | 10 ---------- feincms/module/page/models.py | 3 +++ feincms/module/page/processors.py | 14 +++++++++++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index aabb6b5a6..f46828b88 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -1,6 +1,5 @@ from django.http import Http404 from django.template import Template -from django.utils.cache import add_never_cache_headers from django.utils.datastructures import SortedDict from django.views.generic import DetailView @@ -182,12 +181,3 @@ def finalize_content_types(self, response): r = content.finalize(self.request, response) if r: return r - - # Add never cache headers in case frontend editing is active - if (hasattr(self.request, "COOKIES") - and self.request.COOKIES.get('frontend_editing', False)): - - if hasattr(response, 'add_post_render_callback'): - response.add_post_render_callback(add_never_cache_headers) - else: - add_never_cache_headers(response) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 7dade059e..217ca5f24 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -340,6 +340,9 @@ def path_to_cache_key(path): Page.register_request_processor( processors.frontendediting_request_processor, key='frontend_editing') + Page.register_response_processor( + processors.frontendediting_response_processor, + key='frontend_editing') signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index d9f0e09e0..04665b13d 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -3,6 +3,7 @@ from django.conf import settings as django_settings from django.http import Http404, HttpResponseRedirect +from django.utils.cache import add_never_cache_headers def redirect_request_processor(page, request): @@ -57,6 +58,17 @@ def frontendediting_request_processor(page, request): return response +def frontendediting_response_processor(page, request, response): + # Add never cache headers in case frontend editing is active + if (hasattr(request, 'COOKIES') + and request.COOKIES.get('frontend_editing', False)): + + if hasattr(response, 'add_post_render_callback'): + response.add_post_render_callback(add_never_cache_headers) + else: + add_never_cache_headers(response) + + def etag_request_processor(page, request): """ Short-circuits the request-response cycle if the ETag matches. @@ -119,7 +131,7 @@ def debug_sql_queries_response_processor(verbose=False, file=sys.stderr): Example:: from feincms.module.page import models, processors - models.Page.register_response_procesors( + models.Page.register_response_processor( processors.debug_sql_queries_response_processor(verbose=True), ) """ From 82986bb209bc71665b0dc942529abeb1dc25d31a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 22:22:13 +0200 Subject: [PATCH 0453/1590] Fix copy-pasto --- feincms/module/page/processors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 04665b13d..390831841 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -28,7 +28,7 @@ def extra_context_request_processor(page, request): 'extra_path': '/', }) - url = object.get_absolute_url() + url = page.get_absolute_url() if request.path != url: request._feincms_extra_context.update({ 'in_appcontent_subpage': True, From 9aa70bb0c86419a768df2ea3b29c642a73dd7092 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 22:30:31 +0200 Subject: [PATCH 0454/1590] Fix #314: Fix CKEditor initialization code --- feincms/templates/admin/content/richtext/init_ckeditor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templates/admin/content/richtext/init_ckeditor.html b/feincms/templates/admin/content/richtext/init_ckeditor.html index 44f6da585..32454a8d3 100644 --- a/feincms/templates/admin/content/richtext/init_ckeditor.html +++ b/feincms/templates/admin/content/richtext/init_ckeditor.html @@ -17,7 +17,7 @@ (function($){ contentblock_init_handlers.push(function(){ $('.order-machine textarea.item-richtext, #frontend_editor textarea.item-richtext').each(function(){ - feincms_richtext_add_ckeditor($(this)); + feincms_richtext_add_ckeditor(this); }); contentblock_move_handlers.poorify.push(function(item) { From d0ca3ec33dd0f57011d0e0d48e429c17b4e73a46 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Jun 2012 23:04:09 +0200 Subject: [PATCH 0455/1590] extra_context request processor has to run before redirect request processor --- feincms/module/page/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 217ca5f24..ba32a0112 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -331,10 +331,10 @@ def path_to_cache_key(path): # ------------------------------------------------------------------------ # Our default request processors -Page.register_request_processor(processors.extra_context_request_processor, - key='extra_context') Page.register_request_processor(processors.redirect_request_processor, key='redirect') +Page.register_request_processor(processors.extra_context_request_processor, + key='extra_context') if settings.FEINCMS_FRONTEND_EDITING: Page.register_request_processor( From 949079f5a16fc3c11c6f869a0367e0595484ac27 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 08:13:47 +0200 Subject: [PATCH 0456/1590] Tidy extension: Stop dropping control character warning --- feincms/utils/html/tidy.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/feincms/utils/html/tidy.py b/feincms/utils/html/tidy.py index 00ab3b696..58ab84c9c 100644 --- a/feincms/utils/html/tidy.py +++ b/feincms/utils/html/tidy.py @@ -27,6 +27,7 @@ def tidy_html(html): if not isinstance(html, unicode): raise ValueError("tidyhtml must be called with a Unicode string!") + errors = list() warnings = list() # First, deal with embedded control codes: @@ -64,9 +65,6 @@ def tidy_html(html): # postprocess warnings to avoid HTML fragments being reported as lacking # doctype and title: - errors = list() - warnings = list() - for msg in messages: if not doc_mode and "Warning: missing <!DOCTYPE> declaration" in msg: continue From 487615b453657266d24ec2648a4f1a3619c774de Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 09:43:40 +0200 Subject: [PATCH 0457/1590] Rename ContentMixin to ContentModelMixin --- feincms/module/mixins.py | 2 +- feincms/module/page/models.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index f46828b88..ec66835e1 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -6,7 +6,7 @@ from feincms import settings -class ContentMixin(object): +class ContentModelMixin(object): """ Mixin for ``feincms.models.Base`` subclasses which need need some degree of additional control over the request-response cycle. diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 15bc24796..db0ed132f 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -17,7 +17,7 @@ from feincms import settings from feincms.management.checker import check_database_schema from feincms.models import create_base_model -from feincms.module.mixins import ContentMixin +from feincms.module.mixins import ContentModelMixin from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin @@ -154,7 +154,7 @@ def for_request(self, request, raise404=False, best_match=False, PageManager.add_to_active_filters(Q(active=True)) # ------------------------------------------------------------------------ -class Page(create_base_model(MPTTModel), ContentMixin): +class Page(create_base_model(MPTTModel), ContentModelMixin): active = models.BooleanField(_('active'), default=True) # structure and navigation From 6b49bff4ddb0b856989a8ef784b11d39f74d620e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 10:04:03 +0200 Subject: [PATCH 0458/1590] Add a ContentObjectMixin containing most of ContentView --- feincms/module/mixins.py | 44 +++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index ec66835e1..2c45a57b6 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -1,7 +1,8 @@ from django.http import Http404 from django.template import Template from django.utils.datastructures import SortedDict -from django.views.generic import DetailView +from django.views import generic +from django.views.generic.base import TemplateResponseMixin from feincms import settings @@ -47,18 +48,21 @@ def register_response_processor(cls, fn, key=None): cls.response_processors[fn if key is None else key] = fn -class ContentView(DetailView): - #: The name of the object for the template rendering context - context_object_name = 'feincms_object' +class ContentObjectMixin(TemplateResponseMixin): + """ + Mixin for Django's class based views which knows how to handle + ``ContentModelMixin`` detail pages. + + This is a mixture of Django's ``SingleObjectMixin`` and + ``TemplateResponseMixin`` conceptually to support FeinCMS' + ``ApplicationContent`` inheritance. It does not inherit + ``SingleObjectMixin`` however, because that would set a + precedence for the way how detail objects are determined + (and would f.e. make the page and blog module implementation + harder). + """ - def dispatch(self, request, *args, **kwargs): - if request.method.lower() not in self.http_method_names: - return self.http_method_not_allowed(request, *args, **kwargs) - self.request = request - self.args = args - self.kwargs = kwargs - self.object = self.get_object() - return self.handler(request, *args, **kwargs) + context_object_name = None def handler(self, request, *args, **kwargs): if not hasattr(self.request, '_feincms_extra_context'): @@ -98,8 +102,9 @@ def get_template_names(self): def get_context_data(self, **kwargs): context = self.request._feincms_extra_context - context[self.context_object_name] = self.object - return context + context[self.context_object_name or 'feincms_object'] = self.object + context.update(kwargs) + return super(ContentObjectMixin, self).get_context_data(**context) @property def __name__(self): @@ -181,3 +186,14 @@ def finalize_content_types(self, response): r = content.finalize(self.request, response) if r: return r + + +class ContentView(generic.DetailView, ContentObjectMixin): + def dispatch(self, request, *args, **kwargs): + if request.method.lower() not in self.http_method_names: + return self.http_method_not_allowed(request, *args, **kwargs) + self.request = request + self.args = args + self.kwargs = kwargs + self.object = self.get_object() + return self.handler(request, *args, **kwargs) From 7ddeed1862c02bf7eac33b9f1bf2e90c9ec826fc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 10:04:26 +0200 Subject: [PATCH 0459/1590] Do not raise a 404 on extra_path if already inside an ApplicationContent --- feincms/module/mixins.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 2c45a57b6..6a70eac98 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -170,9 +170,13 @@ def process_content_types(self): # re-raise stored Http404 exception raise http404 - if not settings.FEINCMS_ALLOW_EXTRA_PATH and \ - self.request._feincms_extra_context.get('extra_path', '/') != '/': - raise Http404() + extra_context = self.request._feincms_extra_context + + if (not settings.FEINCMS_ALLOW_EXTRA_PATH + and extra_context.get('extra_path', '/') != '/' + and not extra_context.get('app_config') # Nested ContentModelMixin classes... + ): + raise Http404('Not found') def finalize_content_types(self, response): """ From 680d082479354f63be4204fbfe76fc00017a3032 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 10:13:53 +0200 Subject: [PATCH 0460/1590] Add doubtful comment concerning the extra_path handling change --- feincms/module/mixins.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 6a70eac98..244a69c8d 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -174,7 +174,9 @@ def process_content_types(self): if (not settings.FEINCMS_ALLOW_EXTRA_PATH and extra_context.get('extra_path', '/') != '/' - and not extra_context.get('app_config') # Nested ContentModelMixin classes... + # XXX Already inside application content. I'm not sure + # whether this fix is really correct... + and not extra_context.get('app_config') ): raise Http404('Not found') From 648b9b5b8e3d0dfb13cb642c95f8436ffe9fb06b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 10:16:02 +0200 Subject: [PATCH 0461/1590] Inherit mixins first Thanks mjtamlyn. --- feincms/module/mixins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 244a69c8d..a0a2740b1 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -194,7 +194,7 @@ def finalize_content_types(self, response): return r -class ContentView(generic.DetailView, ContentObjectMixin): +class ContentView(ContentObjectMixin, generic.DetailView): def dispatch(self, request, *args, **kwargs): if request.method.lower() not in self.http_method_names: return self.http_method_not_allowed(request, *args, **kwargs) From f88270f206c482aa249beb1a84eedde51dd3daf5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 11:43:14 +0200 Subject: [PATCH 0462/1590] extensions: Do not crash when only one fieldset is defined --- feincms/extensions.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index ca0f0c928..234b27bed 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -192,4 +192,9 @@ def add_extension_options(self, *f): f[1]['classes'] = list(f[1].get('classes', [])) f[1]['classes'].append('collapse') elif f: # assume called with "other" fields - self.fieldsets[1][1]['fields'].extend(f) + try: + self.fieldsets[1][1]['fields'].extend(f) + except IndexError: + # Fall back to first fieldset if second does not exist + # XXX This is really messy. + self.fieldsets[0][1]['fields'].extend(f) From cd44825e17779fd1c259a220b5c25b8f008c41a4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 11:43:48 +0200 Subject: [PATCH 0463/1590] Content object mixin: Call super get_template_names if unable to handle it ourselves --- feincms/module/mixins.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index a0a2740b1..1810ddc57 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -98,7 +98,12 @@ def get_template_names(self): return [self.template_name] self.object._needs_templates() - return [self.object.template.path] + if self.object.template.path: + return [self.object.template.path] + + # Hopefully someone else has a usable get_template_names() + # implementation... + return super(ContentObjectMixin, self).get_template_names() def get_context_data(self, **kwargs): context = self.request._feincms_extra_context From e5600e2940f2f014f414bdfeab442382a18fda73 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 11:55:36 +0200 Subject: [PATCH 0464/1590] Be a little bit more informative in Http404 exceptions --- feincms/content/application/models.py | 3 ++- feincms/contrib/preview/views.py | 2 +- feincms/module/mixins.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index b84b5452c..2697ccb6d 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -325,7 +325,8 @@ def process(self, request, **kw): fn, args, kwargs = resolve(path, urlconf_path) except (ValueError, Resolver404): del _local.urlconf - raise Resolver404 + raise Resolver404('Not found (resolving %r in %r failed)' % ( + path, urlconf_path)) #: Variables from the ApplicationContent parameters are added to request # so we can expose them to our templates via the appcontent_parameters diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 6ac8d49e1..d5fee39bc 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -28,7 +28,7 @@ def get_object(self): def handler(self, request, *args, **kwargs): if not request.user.is_staff: - raise Http404() + raise Http404('Not found (not allowed)') response = super(PreviewHandler, self).handler(request, *args, **kwargs) response['Cache-Control'] = 'no-cache, must-revalidate, no-store, private' return response diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 1810ddc57..7437b4932 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -183,7 +183,7 @@ def process_content_types(self): # whether this fix is really correct... and not extra_context.get('app_config') ): - raise Http404('Not found') + raise Http404('Not found (unhandled extra_path)') def finalize_content_types(self, response): """ From a54d9b5a30d21246b9d0e974c9512edd59a247eb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 12:33:01 +0200 Subject: [PATCH 0465/1590] PEP8-ify the code a bit --- feincms/content/application/models.py | 103 ++++++++++++++++---------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 2697ccb6d..83d33d10e 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -24,13 +24,15 @@ except ImportError: from django.utils._threading_local import local -_local = local() # Used to store MPTT informations about the currently requested - # page. The information will be used to find the best application - # content instance if a particular application has been added - # more than once to the current website. - # Additionally, we store the page class too, because when we have - # more than one page class, reverse() will want to prefer the page - # class used to render the current page. (See issue #240) +# Used to store MPTT informations about the currently requested +# page. The information will be used to find the best application +# content instance if a particular application has been added +# more than once to the current website. +# Additionally, we store the page class too, because when we have +# more than one page class, reverse() will want to prefer the page +# class used to render the current page. (See issue #240) +_local = local() + def retrieve_page_information(page, request=None): """This is the request processor responsible for retrieving information @@ -46,7 +48,8 @@ def _empty_reverse_cache(): _local.reverse_cache = {} -def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, **vkwargs): +def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, + *vargs, **vkwargs): """ Reverse URLs from application contents @@ -67,11 +70,12 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, # First parameter might be a request instead of an urlconf path, so # we'll try to be helpful and extract the current urlconf from it - appconfig = getattr(urlconf, '_feincms_extra_context', {}).get('app_config', {}) + extra_context = getattr(urlconf, '_feincms_extra_context', {}) + appconfig = extra_context.get('app_config', {}) urlconf = appconfig.get('urlconf_path', urlconf) - # vargs and vkwargs are used to send through additional parameters which are - # uninteresting to us (such as current_app) + # vargs and vkwargs are used to send through additional parameters which + # are uninteresting to us (such as current_app) # get additional cache keys from the page if available # refs https://github.com/feincms/feincms/pull/277/ @@ -86,8 +90,10 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, if proximity_info: app_cache_keys.update({ - 'all': '%s:app_%s_%s_%s_%s_%s' % ((cache_key_prefix, urlconf,) + proximity_info), - 'tree': '%s:app_%s_%s' % (cache_key_prefix, urlconf, proximity_info[0]), + 'all': '%s:app_%s_%s_%s_%s_%s' % ( + (cache_key_prefix, urlconf,) + proximity_info), + 'tree': '%s:app_%s_%s' % ( + cache_key_prefix, urlconf, proximity_info[0]), }) for key in ('all', 'tree', 'none'): @@ -108,7 +114,8 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, model_class = ApplicationContent._feincms_content_models[0] # TODO: Only active pages? What about multisite support? - contents = model_class.objects.filter(urlconf_path=urlconf).select_related('parent') + contents = model_class.objects.filter( + urlconf_path=urlconf).select_related('parent') if proximity_info: # find the closest match within the same subtree @@ -155,9 +162,6 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, if not hasattr(_local, 'reverse_cache'): _local.reverse_cache = {} - # Reimplementation of Page.get_absolute_url because we are quite likely - # to hit infinite recursion if we call models.permalink because of the - # reverse monkey patch url = content.parent._cached_url[1:-1] if url: prefix = reverse('feincms_handler', args=(url,)) @@ -177,7 +181,7 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, *vargs, kwargs=kwargs, prefix=url_prefix[1], *vargs, **vkwargs) - raise NoReverseMatch("Unable to find ApplicationContent for '%s'" % urlconf) + raise NoReverseMatch("Unable to find ApplicationContent for %r" % urlconf) #: Lazy version of ``app_reverse`` @@ -195,7 +199,7 @@ def permalink(func): class MyModel(models.Model): @appmodels.permalink def get_absolute_url(self): - return ('myapp.urls', 'mymodel_detail', (), {'slug': self.slug}) + return ('myapp.urls', 'model_detail', (), {'slug': self.slug}) """ def inner(*args, **kwargs): return app_reverse(*func(*args, **kwargs)) @@ -222,7 +226,10 @@ class Meta: def initialize_type(cls, APPLICATIONS): for i in APPLICATIONS: if not 2 <= len(i) <= 3: - raise ValueError("APPLICATIONS must be provided with tuples containing at least two parameters (urls, name) and an optional extra config dict") + raise ValueError( + "APPLICATIONS must be provided with tuples containing at" + " least two parameters (urls, name) and an optional extra" + " config dict") urls, name = i[0:2] @@ -230,7 +237,9 @@ def initialize_type(cls, APPLICATIONS): app_conf = i[2] if not isinstance(app_conf, dict): - raise ValueError("The third parameter of an APPLICATIONS entry must be a dict or the name of one!") + raise ValueError( + "The third parameter of an APPLICATIONS entry must be" + " a dict or the name of one!") else: app_conf = {} @@ -241,7 +250,8 @@ def initialize_type(cls, APPLICATIONS): } cls.add_to_class('urlconf_path', - models.CharField(_('application'), max_length=100, choices=[(c['urls'], c['name']) for c in cls.ALL_APPS_CONFIG.values()]) + models.CharField(_('application'), max_length=100, choices=[ + (c['urls'], c['name']) for c in cls.ALL_APPS_CONFIG.values()]) ) class ApplicationContentItemEditorForm(ItemEditorForm): @@ -256,19 +266,22 @@ def __init__(self, *args, **kwargs): if instance: try: # TODO use urlconf_path from POST if set - # urlconf_path = request.POST.get('...urlconf_path', instance.urlconf_path) - self.app_config = cls.ALL_APPS_CONFIG[instance.urlconf_path]['config'] + # urlconf_path = request.POST.get('...urlconf_path', + # instance.urlconf_path) + self.app_config = cls.ALL_APPS_CONFIG[ + instance.urlconf_path]['config'] except KeyError: self.app_config = {} self.custom_fields = {} - admin_fields = self.app_config.get('admin_fields', {}) + admin_fields = self.app_config.get('admin_fields', {}) if isinstance(admin_fields, dict): self.custom_fields.update(admin_fields) else: get_fields = get_object(admin_fields) - self.custom_fields.update(get_fields(self, *args, **kwargs)) + self.custom_fields.update( + get_fields(self, *args, **kwargs)) for k, v in self.custom_fields.items(): self.fields[k] = v @@ -279,24 +292,29 @@ def save(self, commit=True, *args, **kwargs): # get the model so we can set .parameters to the values of our # custom fields before calling save(commit=True) - m = super(ApplicationContentItemEditorForm, self).save(commit=False, *args, **kwargs) + m = super(ApplicationContentItemEditorForm, self).save( + commit=False, *args, **kwargs) - m.parameters = dict((k, self.cleaned_data[k]) for k in self.custom_fields if k in self.cleaned_data) + m.parameters = dict((k, self.cleaned_data[k]) for k + in self.custom_fields if k in self.cleaned_data) if commit: m.save(**kwargs) return m - #: This provides hooks for us to customize the admin interface for embedded instances: + # This provides hooks for us to customize the admin interface for + # embedded instances: cls.feincms_item_editor_form = ApplicationContentItemEditorForm # Make sure the patched reverse() method has all information it needs - cls.parent.field.rel.to.register_request_processor(retrieve_page_information) + cls.parent.field.rel.to.register_request_processor( + retrieve_page_information) def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) - self.app_config = self.ALL_APPS_CONFIG.get(self.urlconf_path, {}).get('config', {}) + self.app_config = self.ALL_APPS_CONFIG.get( + self.urlconf_path, {}).get('config', {}) def process(self, request, **kw): page_url = self.parent.get_absolute_url() @@ -328,14 +346,15 @@ def process(self, request, **kw): raise Resolver404('Not found (resolving %r in %r failed)' % ( path, urlconf_path)) - #: Variables from the ApplicationContent parameters are added to request - # so we can expose them to our templates via the appcontent_parameters - # context_processor + # Variables from the ApplicationContent parameters are added to request + # so we can expose them to our templates via the appcontent_parameters + # context_processor request._feincms_extra_context.update(self.parameters) # Save the application configuration for reuse elsewhere - request._feincms_extra_context.update({'app_config': dict(self.app_config, - urlconf_path=self.urlconf_path)}) + request._feincms_extra_context.update({ + 'app_config': dict(self.app_config, + urlconf_path=self.urlconf_path)}) view_wrapper = self.app_config.get("view_wrapper", None) if view_wrapper: @@ -384,8 +403,10 @@ def send_directly(self, request, response): mimetype = mimetype.split(';')[0] mimetype = mimetype.strip() - return (response.status_code != 200 or request.is_ajax() or getattr(response, 'standalone', False) or - mimetype not in ('text/html', 'text/plain')) + return (response.status_code != 200 + or request.is_ajax() + or getattr(response, 'standalone', False) + or mimetype not in ('text/html', 'text/plain')) def render(self, **kwargs): return getattr(self, 'rendered_result', u'') @@ -412,9 +433,9 @@ def _update_response_headers(self, request, response, headers): """ from django.utils.http import http_date - # Ideally, for the Cache-Control header, we'd want to do some intelligent - # combining, but that's hard. Let's just collect and unique them and let - # the client worry about that. + # Ideally, for the Cache-Control header, we'd want to do some + # intelligent combining, but that's hard. Let's just collect and unique + # them and let the client worry about that. cc_headers = set(('must-revalidate',)) for x in (cc.split(",") for cc in headers.get('Cache-Control', ())): cc_headers |= set((s.strip() for s in x)) From b5d7700930a00d8a5a92a828b6bf9b5b6754009b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 12:35:29 +0200 Subject: [PATCH 0466/1590] Replace reverse calls for pages with get_absolute_url --- feincms/content/application/models.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 83d33d10e..8c6d3bdbe 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -162,14 +162,8 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, if not hasattr(_local, 'reverse_cache'): _local.reverse_cache = {} - url = content.parent._cached_url[1:-1] - if url: - prefix = reverse('feincms_handler', args=(url,)) - # prefix must always ends with a slash - prefix += '/' if prefix[-1] != '/' else '' - - else: - prefix = reverse('feincms_home') + prefix = content.parent.get_absolute_url() + prefix += '/' if prefix[-1] != '' else '' _local.reverse_cache[app_cache_keys[cache_key]] = url_prefix = ( urlconf, prefix) From 502461b64a41ebac699b205cdf576ad92ba0393b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 12:36:45 +0200 Subject: [PATCH 0467/1590] Stop adding and removing _local.urlconf, the monkey patch is no more --- feincms/content/application/models.py | 58 +++++++++++---------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 8c6d3bdbe..af0b620ab 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -330,13 +330,9 @@ def process(self, request, **kw): # Resolve the module holding the application urls. urlconf_path = self.app_config.get('urls', self.urlconf_path) - # Change the prefix and urlconf for the monkey-patched reverse function ... - _local.urlconf = (urlconf_path, page_url) - try: fn, args, kwargs = resolve(path, urlconf_path) except (ValueError, Resolver404): - del _local.urlconf raise Resolver404('Not found (resolving %r in %r failed)' % ( path, urlconf_path)) @@ -358,36 +354,30 @@ def process(self, request, **kw): appcontent_parameters=self.parameters ) - try: - output = fn(request, *args, **kwargs) - - if isinstance(output, HttpResponse): - if self.send_directly(request, output): - return output - elif output.status_code == 200: - - # If the response supports deferred rendering, render the - # response right now. We do not handle template response - # middleware. - if hasattr(output, 'render') and callable(output.render): - output.render() - - self.rendered_result = mark_safe(output.content.decode('utf-8')) - self.rendered_headers = {} - # Copy relevant headers for later perusal - for h in ('Cache-Control', 'Last-Modified', 'Expires'): - if h in output: - self.rendered_headers.setdefault(h, []).append(output[h]) - elif isinstance(output, tuple) and 'view' in kw: - kw['view'].template_name = output[0] - kw['view'].request._feincms_extra_context.update(output[1]) - else: - self.rendered_result = mark_safe(output) - - finally: - # We want exceptions to propagate, but we cannot allow the - # modifications to reverse() to stay here. - del _local.urlconf + output = fn(request, *args, **kwargs) + + if isinstance(output, HttpResponse): + if self.send_directly(request, output): + return output + elif output.status_code == 200: + + # If the response supports deferred rendering, render the + # response right now. We do not handle template response + # middleware. + if hasattr(output, 'render') and callable(output.render): + output.render() + + self.rendered_result = mark_safe(output.content.decode('utf-8')) + self.rendered_headers = {} + # Copy relevant headers for later perusal + for h in ('Cache-Control', 'Last-Modified', 'Expires'): + if h in output: + self.rendered_headers.setdefault(h, []).append(output[h]) + elif isinstance(output, tuple) and 'view' in kw: + kw['view'].template_name = output[0] + kw['view'].request._feincms_extra_context.update(output[1]) + else: + self.rendered_result = mark_safe(output) return True # successful From 9fd3159237c57188bfaa039ff95f9064f5b5fdb0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 12:37:28 +0200 Subject: [PATCH 0468/1590] Remove a left-over comment --- feincms/content/application/models.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index af0b620ab..c17408f69 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -313,8 +313,6 @@ def __init__(self, *args, **kwargs): def process(self, request, **kw): page_url = self.parent.get_absolute_url() - # Get the rest of the URL - # Provide a way for appcontent items to customize URL processing by # altering the perceived path of the page: if "path_mapper" in self.app_config: From 28d724a3b41d4fcfb5e30b755633d78ada2e7649 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 12:39:50 +0200 Subject: [PATCH 0469/1590] ApplicationContent: Replace overridden save/delete methods with signals --- feincms/content/application/models.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index c17408f69..8bad55aaf 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -9,6 +9,7 @@ from django.core import urlresolvers from django.core.urlresolvers import Resolver404, resolve, reverse, NoReverseMatch from django.db import models +from django.db.models import signals from django.http import HttpResponse from django.utils.functional import curry as partial, lazy, wraps from django.utils.safestring import mark_safe @@ -44,7 +45,7 @@ def retrieve_page_information(page, request=None): _local.page_cache_key_fn = page.cache_key -def _empty_reverse_cache(): +def _empty_reverse_cache(*args, **kwargs): _local.reverse_cache = {} @@ -305,6 +306,9 @@ def save(self, commit=True, *args, **kwargs): cls.parent.field.rel.to.register_request_processor( retrieve_page_information) + signals.post_save.connect(_empty_reverse_cache, sender=cls) + signals.post_delete.connect(_empty_reverse_cache, sender=cls) + def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) self.app_config = self.ALL_APPS_CONFIG.get( @@ -398,16 +402,6 @@ def finalize(self, request, response): if headers: self._update_response_headers(request, response, headers) - def save(self, *args, **kwargs): - super(ApplicationContent, self).save(*args, **kwargs) - # Clear reverse() cache - _empty_reverse_cache() - - def delete(self, *args, **kwargs): - super(ApplicationContent, self).delete(*args, **kwargs) - # Clear reverse() cache - _empty_reverse_cache() - def _update_response_headers(self, request, response, headers): """ Combine all headers that were set by the different content types From b304c44aa43f0c025e4a187c951fd430f56efcb8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 12:39:58 +0200 Subject: [PATCH 0470/1590] Rewrap another two long lines --- feincms/content/application/models.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 8bad55aaf..4d2d8dd1d 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -369,12 +369,16 @@ def process(self, request, **kw): if hasattr(output, 'render') and callable(output.render): output.render() - self.rendered_result = mark_safe(output.content.decode('utf-8')) + self.rendered_result = mark_safe( + output.content.decode('utf-8')) self.rendered_headers = {} + # Copy relevant headers for later perusal for h in ('Cache-Control', 'Last-Modified', 'Expires'): if h in output: - self.rendered_headers.setdefault(h, []).append(output[h]) + self.rendered_headers.setdefault( + h, []).append(output[h]) + elif isinstance(output, tuple) and 'view' in kw: kw['view'].template_name = output[0] kw['view'].request._feincms_extra_context.update(output[1]) From 39aab5dcd810916002ce34ba5250d32a9d536e20 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 12:57:20 +0200 Subject: [PATCH 0471/1590] Even more informative Http404 exception when extra_path is unhandled --- feincms/module/mixins.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 7437b4932..daff34288 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -183,7 +183,10 @@ def process_content_types(self): # whether this fix is really correct... and not extra_context.get('app_config') ): - raise Http404('Not found (unhandled extra_path)') + raise Http404('Not found (extra_path %r on %r)' % ( + extra_context.get('extra_path', '/'), + self.object, + )) def finalize_content_types(self, response): """ From 46b0ca20c88176eef1bdbefbea14a4f832cc10f6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 14:33:52 +0200 Subject: [PATCH 0472/1590] Fix handle_model method signature --- feincms/extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 234b27bed..0af2a5b56 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -114,7 +114,7 @@ def __init__(self, model, **kwargs): self.handle_model() - def handle_model(self, model): + def handle_model(self): raise NotImplementedError def handle_modeladmin(self, modeladmin): From 3466da6353aa095d5d533cc6240b9ec8587b438e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 14:34:10 +0200 Subject: [PATCH 0473/1590] Work on release notes for 1.7 --- docs/deprecation.rst | 4 ++ docs/releases/1.7.rst | 137 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 136 insertions(+), 5 deletions(-) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index 4354baeee..bb793ccd8 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -47,6 +47,8 @@ will be issued for at least two releases. the contents of :mod:`feincms.content.medialibrary.v2`. The latter uses Django's ``raw_id_fields`` support instead of reimplementing it badly. +* The legacy views inside :mod:`feincms.views.legacy` will be removed. + 1.8 === @@ -81,3 +83,5 @@ will be issued for at least two releases. * The module :mod:`feincms.content.medialibrary.v2`, which is only an alias for :mod:`feincms.content.medialibrary.models` starting with FeinCMS v1.7 will be removed. + +* ``Page.setup_request()`` does not do anything anymore and will be removed. diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index da84439c3..9c9631fba 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -5,10 +5,112 @@ FeinCMS 1.7 release notes (upcoming) Welcome to FeinCMS 1.7! +Extensions-mechanism refactor +============================= + +The extensions mechanism has been refactored to remove the need to make models +know about their related model admin classes. The new module +:py:mod:`feincms.extensions` contains mixins and base classes - their purpose +is as follows: + +.. class:: feincms.extensions.ExtensionsMixin + + This mixin provides the ``register_extensions`` method which is the place + where extensions are registered for a certain model. Extensions can be + specified in the following ways: + + - Subclasses of :py:class:`~feincms.extensions.Extension` + - Dotted Python module paths pointing to a subclass of the aforementioned + extension class + - Dotted Python module paths pointing to a module containing either a class + named ``Extension`` or a function named ``register`` (for legacy + extensions) + + +.. class:: feincms.extensions.Extension + + This is the base class for your own extension. It has the following methods + and properties: + + .. attribute:: model + + The model class. + + .. method:: handle_model(self) + + The method which modifies the Django model class. The model class is + available as ``self.model``. + + .. method:: handle_modeladmin(self, modeladmin) + + This method receives the model admin instance bound to the model. This + method could be called more than once, especially when using more than + one admin site. + + +.. class:: feincms.extensions.ExtensionModelAdmin() + + This is a model admin subclass which knows about extensions, and lets the + extensions do their work modifying the model admin instance after it has + been successfully initialized. It has the following methods and properties: + + .. method:: initialize_extensions(self) + + This method is automatically called at the end of initialization and + loops through all registered extensions and calls their + ``handle_modeladmin`` method. + + .. method:: add_extension_options(self, \*f) + + This is a helper to add fields and fieldsets to a model admin instance. + Usage is as follows:: + + modeladmin.add_extension_options('field1', 'field2') + + Or:: + + modeladmin.add_extension_options(_('Fieldset title'), { + 'fields': ('field1', 'field2'), + }) + + +View code refactor +================== + +Made views, content type and request / response processors reusable. + +The legacy views at :py:mod:`feincms.views.legacy` did were considered +unhelpful and were removed. + + Backwards-incompatible changes ============================== +Page manager methods behavior +----------------------------- + +Previously, the following page manager methods sometimes returned inactive +objects or did not raise the appropriate (and asked for) +:py:class:`~django.http.Http404` exception: + +- ``Page.objects.page_for_path`` +- ``Page.objects.best_match_for_path`` +- ``Page.objects.for_request`` + +The reason for that was that only the page itself was tested for activity +in the manager method, and none of its ancestors. The check whether all +ancestors are active was only conducted later in a request processor. This +request processor was registered by default and was always run when +``Page.objects.for_request`` was called with ``setup=True``. + +However, request processors do not belong into the model layer. The necessity +of running code belonging to a request-response cycle to get the correct answer +from a manager method was undesirable. This has been rectified, those manager +methods check the ancestry directly. The now redundant request processor +``require_path_active_request_processor`` has been removed. + + Reversing application content URLs ---------------------------------- @@ -19,16 +121,22 @@ The support for monkey-patching applicationcontent-awareness into Django's Removal of deprecated features ------------------------------ +* The old media library content type module + :py:mod:`feincms.content.medialibrary.models` has been replaced with the + contents of :py:mod:`feincms.content.medialibrary.v2`. The model field + ``position`` has been renamed to ``type``, instead of ``POSITION_CHOICES`` + you should use ``TYPE_CHOICES`` now. The code has been simplified and + hacks to imitate ``raw_id_fields`` have been replaced by working stock + code. The ``v2`` module will stay around for another release and will be + removed in FeinCMS v1.8. The now-unused template + ``admin/content/mediafile/init.html`` has been deleted. New deprecations ---------------- - -Compatibility with Django and other apps ----------------------------------------- - -FeinCMS 1.7 requires Django 1.4. +* ``Page.setup_request()`` does not do anything anymore and will be removed + in FeinCMS v1.8. Notable features and improvements @@ -38,7 +146,26 @@ Notable features and improvements is now available, :py:func:`~feincms.content.application.models.app_reverse_lazy`. +* Because of the extensions refactor mentioned above, all + ``register_extension`` methods have been removed. Additionally, the model + admin classes are not imported inside the ``models.py`` files anymore. Bugfixes ======== + +* It should be possible to store FeinCMS models in a secondary database, as + long as the base model and all content types are stored in the same + database. + +* Changing templates in the item editor where the templates do not share + common regions does not result in orphaned content blocks anymore. + +* :py:func:`feincms.utils.get_object` knows how to import modules, not only + objects inside modules now. + + +Compatibility with Django and other apps +======================================== + +FeinCMS 1.7 requires Django 1.4. From 0a5ca9a87e89fc91aadb59950273a4f30d38cf0f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 17:58:04 +0200 Subject: [PATCH 0474/1590] Fix typo in app_reverse which could lead to repeated slashes --- feincms/content/application/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 4d2d8dd1d..486a1946a 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -164,7 +164,7 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, _local.reverse_cache = {} prefix = content.parent.get_absolute_url() - prefix += '/' if prefix[-1] != '' else '' + prefix += '/' if prefix[-1] != '/' else '' _local.reverse_cache[app_cache_keys[cache_key]] = url_prefix = ( urlconf, prefix) From d8a6e2711a47e5d69dac70ecdbd122711b0becf9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Jun 2012 08:55:56 +0200 Subject: [PATCH 0475/1590] Fix #318: feincms_nav should fail gracefully Thanks to Simon Meers for the suggestion and the fix. --- feincms/module/page/templatetags/feincms_page_tags.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 1badbd99d..6999fc47e 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -27,7 +27,11 @@ def feincms_nav(context, feincms_page, level=1, depth=1): """ if isinstance(feincms_page, HttpRequest): - feincms_page = Page.objects.for_request(feincms_page, best_match=True) + try: + feincms_page = Page.objects.for_request( + feincms_page, best_match=True) + except Page.DoesNotExist: + return [] mptt_opts = feincms_page._mptt_meta From 7e52496644d1ec25fd6e2bf3280674398b4e79f2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Jun 2012 09:04:15 +0200 Subject: [PATCH 0476/1590] Clarify the feincms_nav extensions handling code a bit --- .../module/page/templatetags/feincms_page_tags.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 6999fc47e..2b59c869f 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -91,8 +91,10 @@ def _filter(iterable): def _filter(iterable): for elem in iterable: + elem_right = getattr(elem, mptt_opts.right_attr) + if extended_node_rght: - if getattr(elem, mptt_opts.right_attr) < extended_node_rght[-1]: + if elem_right < extended_node_rght[-1]: # Still inside some navigation extension continue else: @@ -100,11 +102,17 @@ def _filter(iterable): if getattr(elem, 'navigation_extension', None): yield elem - extended_node_rght.append(getattr(elem, mptt_opts.right_attr)) + extended_node_rght.append(elem_right) for extended in elem.extended_navigation(depth=depth, request=context.get('request')): - if getattr(extended, mptt_opts.level_attr, 0) < level + depth - 1: + + # Only return items from the extended navigation which + # are inside the requested level+depth values. The + # "-1" accounts for the differences in MPTT and + # navigation level counting + this_level = getattr(extended, mptt_opts.level_attr, 0) + if this_level < level + depth - 1: yield extended else: From 5b59f9b7ef7d9bd976b8261ddb0e0f1c9748b4c8 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 25 Jun 2012 17:16:48 +1000 Subject: [PATCH 0477/1590] `FORMAT_CHOICES` can't actually accept blank strings. This should no-op. --- feincms/content/image/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index cbb0f3466..9200f50fa 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -28,7 +28,7 @@ class ImageContent(models.Model): ('right', 'Right'), ), FORMAT_CHOICES=( - ('', 'Do not resize'), + ('cropscale', 'Do not resize'), ('cropscale:100x100', 'Square Thumbnail'), ('cropscale:200x450', 'Medium Portait'), ('thumbnail:1000x1000', 'Large'), From 708e849987255d21f0dd6130725e253b6f50b578 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Jun 2012 09:49:06 +0200 Subject: [PATCH 0478/1590] FeinCMS v1.6.2 We've accumulated enough fixes for another point release. --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 21e077e5e..4d631445c 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 6, 1) +VERSION = (1, 6, 2) __version__ = '.'.join(map(str, VERSION)) From 3a32454b1412a574c4145ad1a6ab36ae6a290e10 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Jun 2012 10:13:20 +0200 Subject: [PATCH 0479/1590] Clarify the FORMAT_CHOICES parameter a bit as per the discussion on #320 --- feincms/content/image/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index 9200f50fa..48652ed03 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -28,7 +28,7 @@ class ImageContent(models.Model): ('right', 'Right'), ), FORMAT_CHOICES=( - ('cropscale', 'Do not resize'), + ('noop', 'Do not resize'), ('cropscale:100x100', 'Square Thumbnail'), ('cropscale:200x450', 'Medium Portait'), ('thumbnail:1000x1000', 'Large'), @@ -36,7 +36,8 @@ class ImageContent(models.Model): Note that FORMAT_CHOICES is optional. The part before the colon corresponds to the template filters in the ``feincms_thumbnail`` - template filter library. + template filter library. Known values are ``cropscale`` and + ``thumbnail``. Everything else (such as ``noop``) is ignored. """ image = models.ImageField( From a8d217449addf489dbd66d9c7ec8046f11a98b4b Mon Sep 17 00:00:00 2001 From: Marc Egli <frog32@me.com> Date: Thu, 8 Mar 2012 14:47:19 +0100 Subject: [PATCH 0480/1590] fix the app_reverse templatetag to work in the following situation {% app_reverse "url_name" "myapp.urls" as my_url_var %} --- feincms/templatetags/applicationcontent_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index f62b17a1f..a5a7403f1 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -103,7 +103,7 @@ def app_reverse(parser, token): kwargs = {} asvar = None bits = bits[3:] - if len(bits) >= 3 and bits[-2] == 'as': + if len(bits) >= 2 and bits[-2] == 'as': asvar = bits[-1] bits = bits[:-2] From 97888b8f82024a741096a30d166135d1f7083f5f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Jun 2012 16:43:32 +0200 Subject: [PATCH 0481/1590] FeinCMS v1.5.6 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 614cc6e4d..68bcb07bd 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 5, 5) +VERSION = (1, 5, 6) __version__ = '.'.join(map(str, VERSION)) From b91e892c7a1c24fa23ad29e2ab2467671b22e13e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 28 Jun 2012 08:39:21 +0200 Subject: [PATCH 0482/1590] feincms_nav: Fix regression with level=somewhere deep in the tree Thanks to Daniel Mettler for the report. --- feincms/module/page/templatetags/feincms_page_tags.py | 7 +++++++ feincms/tests/page_tests.py | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 95deba9e4..83b49f9af 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -56,6 +56,13 @@ def feincms_nav(context, feincms_page, level=1, depth=1): # The requested pages start somewhere higher up in the tree parent = feincms_page.get_ancestors()[level - 2] + elif level - 1 > page_level: + # The requested pages are grandchildren of the current page + # (or even deeper in the tree). If we would continue processing, + # this would result in pages from different subtrees being + # returned directly adjacent to each other. + queryset = Page.objects.none() + if parent: # Special case for navigation extensions if getattr(parent, 'navigation_extension', None): diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index daa729ff4..c76257816 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -791,6 +791,11 @@ def test_17_feincms_navigation(self): '{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', ), + ( + {'feincms_page': Page.objects.get(pk=1)}, + '{% load feincms_page_tags %}{% feincms_nav feincms_page level=3 depth=1 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', + '', + ), ] for c, t, r in tests: From 7c5374a6eb325364a60205d54c4782157c0049b4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Jun 2012 21:14:22 +0200 Subject: [PATCH 0483/1590] Support nested ContentObjectMixin processing Convert extra_path into a list. Nested ContentObjectMixins make this necessary, for example elephantblog entries inside application contents on page. --- feincms/content/application/models.py | 6 +++++- feincms/module/mixins.py | 8 ++------ feincms/module/page/processors.py | 8 ++++---- feincms/module/page/templatetags/feincms_page_tags.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 486a1946a..940acfc5f 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -327,7 +327,7 @@ def process(self, request, **kw): appcontent_parameters=self.parameters ) else: - path = request._feincms_extra_context['extra_path'] + path = request._feincms_extra_context['extra_path'][-1] # Resolve the module holding the application urls. urlconf_path = self.app_config.get('urls', self.urlconf_path) @@ -356,7 +356,11 @@ def process(self, request, **kw): appcontent_parameters=self.parameters ) + # TODO actually determine the remaining part + request._feincms_extra_context['extra_path'].append('/') output = fn(request, *args, **kwargs) + request._feincms_extra_context['extra_path'] = ( + request._feincms_extra_context['extra_path'][:-1]) if isinstance(output, HttpResponse): if self.send_directly(request, output): diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index daff34288..6e6ced3ed 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -178,13 +178,9 @@ def process_content_types(self): extra_context = self.request._feincms_extra_context if (not settings.FEINCMS_ALLOW_EXTRA_PATH - and extra_context.get('extra_path', '/') != '/' - # XXX Already inside application content. I'm not sure - # whether this fix is really correct... - and not extra_context.get('app_config') - ): + and extra_context.get('extra_path', ['/'])[-1] != '/'): raise Http404('Not found (extra_path %r on %r)' % ( - extra_context.get('extra_path', '/'), + extra_context.get('extra_path'), self.object, )) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 390831841..609ee08ef 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -13,7 +13,7 @@ def redirect_request_processor(page, request): """ target = page.get_redirect_to_target(request) if target: - if request._feincms_extra_context.get('extra_path', '/') == '/': + if request._feincms_extra_context.get('extra_path', ['/'])[0] == '/': return HttpResponseRedirect(target) raise Http404() @@ -25,15 +25,15 @@ def extra_context_request_processor(page, request): request._feincms_extra_context.update({ # XXX This variable name isn't accurate anymore. 'in_appcontent_subpage': False, - 'extra_path': '/', + 'extra_path': ['/'], }) url = page.get_absolute_url() if request.path != url: request._feincms_extra_context.update({ 'in_appcontent_subpage': True, - 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', - request.path), + 'extra_path': [re.sub('^' + re.escape(url.rstrip('/')), '', + request.path)], }) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 2b59c869f..b497bd825 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -234,7 +234,7 @@ def what(self, page, args): request = args.get('request', None) if request: # Trailing path without first slash - trailing_path = request._feincms_extra_context.get('extra_path', '')[1:] + trailing_path = request._feincms_extra_context.get('extra_path', ['/'])[0][1:] translations = dict((t.language, t) for t in page.available_translations()) translations[page.language] = page From debd61210f5efeb861ae8468761015f4f3acb973 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 1 Jul 2012 12:09:19 +0200 Subject: [PATCH 0484/1590] Switch from mimetype to content_type when initializing HttpResponse objects Refs Django issue #16519. --- feincms/admin/tree_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 0fab1ae47..adac3149e 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -320,7 +320,7 @@ def _toggle_boolean(self, request): d.append(b) # TODO: Shorter: [ y for x,y in zip(a,b) if x!=y ] - return HttpResponse(json.dumps(d), mimetype="application/json") + return HttpResponse(json.dumps(d), content_type="application/json") def get_changelist(self, request, **kwargs): return ChangeList From 05de5f3c951f334cc7a3f6dfbe780942d801e176 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn <marc.tamlyn@gmail.com> Date: Mon, 2 Jul 2012 14:30:00 +0100 Subject: [PATCH 0485/1590] Fix RichTextField form field generation. All standard properties that would affect formfield were being ignored (such as blank=True). --- feincms/contrib/richtext.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/contrib/richtext.py b/feincms/contrib/richtext.py index 3e30dbc94..28f017dc3 100644 --- a/feincms/contrib/richtext.py +++ b/feincms/contrib/richtext.py @@ -19,7 +19,8 @@ class RichTextField(models.TextField): Drop-in replacement for Django's ``models.TextField`` which allows editing rich text instead of plain text in the item editor. """ - formfield = RichTextFormField + def formfield(self, form_class=RichTextFormField, **kwargs): + return super(RichTextField, self).formfield(form_class=form_class, **kwargs) try: From 3e391fd0e7177a7cc522d30c041737753bfbc41e Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Tue, 3 Jul 2012 22:33:52 +1000 Subject: [PATCH 0486/1590] No need for 'position' field to be mandatory. --- feincms/content/image/models.py | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index 48652ed03..6c998115f 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -24,8 +24,9 @@ class ImageContent(models.Model): Cls.create_content_type( ImageContent, POSITION_CHOICES=( - ('left', 'Left'), - ('right', 'Right'), + ('left', 'Float to left'), + ('right', 'Float to right'), + ('block', 'Block'), ), FORMAT_CHOICES=( ('noop', 'Do not resize'), @@ -54,10 +55,13 @@ class Meta: verbose_name_plural = _('images') def render(self, **kwargs): - return render_to_string([ - 'content/image/%s.html' % self.position, - 'content/image/default.html', - ], {'content': self}, context_instance=kwargs.get('context')) + templates = ['content/image/default.html'] + if hasattr(self, 'position'): + templates.insert(0, 'content/image/%s.html' % self.position) + return render_to_string( + templates, + {'content': self}, + context_instance=kwargs.get('context')) def get_image(self): type, separator, size = getattr(self, 'format', '').partition(':') @@ -71,17 +75,13 @@ def get_image(self): @classmethod def initialize_type(cls, POSITION_CHOICES=None, FORMAT_CHOICES=None): - if POSITION_CHOICES is None: - raise ImproperlyConfigured( - 'You need to set POSITION_CHOICES when creating a %s' % - cls.__name__) - - models.CharField( - _('position'), - max_length=10, - choices=POSITION_CHOICES, - default=POSITION_CHOICES[0][0] - ).contribute_to_class(cls, 'position') + if POSITION_CHOICES: + models.CharField( + _('position'), + max_length=10, + choices=POSITION_CHOICES, + default=POSITION_CHOICES[0][0] + ).contribute_to_class(cls, 'position') if FORMAT_CHOICES: models.CharField( From ef585d010f2f1783174fd4650dbab65e6f392057 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Tue, 3 Jul 2012 22:51:16 +1000 Subject: [PATCH 0487/1590] Also conditionally use content.position in ImageContent template. --- feincms/templates/content/image/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templates/content/image/default.html b/feincms/templates/content/image/default.html index 64d795dec..2f1f1988d 100644 --- a/feincms/templates/content/image/default.html +++ b/feincms/templates/content/image/default.html @@ -1 +1 @@ -<div class="image-content image-content-{{ content.position }}{% if content.format %} image-content-format-{{ content.format|slugify }}{% endif %}"><img src="{{ content.get_image.url }}" alt="{{ content.alt_text }}" />{% if content.caption %}<div class="caption">{{ content.caption }}</div>{% endif %}</div> +<div class="image-content{% if content.position %} image-content-{{ content.position }}{% endif %}{% if content.format %} image-content-format-{{ content.format|slugify }}{% endif %}"><img src="{{ content.get_image.url }}" alt="{{ content.alt_text }}" />{% if content.caption %}<div class="caption">{{ content.caption }}</div>{% endif %}</div> From 7f2094696384d6e4459db4ccc946a6a270512182 Mon Sep 17 00:00:00 2001 From: Charlie Denton <charlie@meshy.co.uk> Date: Thu, 5 Jul 2012 11:19:55 +0200 Subject: [PATCH 0488/1590] Fix oddity in docs. --- docs/integration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integration.rst b/docs/integration.rst index 7179cac51..66676b49b 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -133,7 +133,7 @@ Writing the models ------------------ Because the URLconf entries ``entry_list`` and ``entry_detail`` aren't -reachable through standard means (remember, they aren't ``include``d +reachable through standard means (remember, they aren't ``include``\d anywhere) it's not possible to use standard ``reverse`` calls to determine the absolute URL of a news entry. FeinCMS provides its own ``app_reverse`` function (see :ref:`integration-reversing-urls` for From 0bb97fb9d86dc9aa5971e4b16f4eb575b9b1dad3 Mon Sep 17 00:00:00 2001 From: Psyton <psyton@vipbox.org> Date: Sun, 8 Jul 2012 15:47:45 +0700 Subject: [PATCH 0489/1590] Fixed psges priority for sitemap --- feincms/module/page/sitemap.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index e3b6ed144..2ed59a392 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -56,8 +56,6 @@ def items(self): if self.depth_cutoff > 0: self.max_depth = min(self.depth_cutoff, self.max_depth) - self.per_level = 1.0 / (self.max_depth + 1.0) - qs = base_qs.filter(redirect_to="") if self.filter: qs = self.filter(qs) @@ -70,9 +68,19 @@ def items(self): if self.extended_navigation: for idx, page in enumerate(pages): + if self.depth_cutoff > 0 and page.level == self.max_depth: + continue if getattr(page, 'navigation_extension', None): - pages[idx + 1:idx + 1] = page.extended_navigation() + for p in page.extended_navigation(): + depth_too_deep = self.depth_cutoff > 0 and p.level > self.depth_cutoff + not_in_nav = self.navigation_only and not p.in_navigation + if depth_too_deep or not_in_nav: + continue + pages.insert(idx + 1, p) + if p.level > self.max_depth: + self.max_depth = p.level + self.per_level = 1.0 / (self.max_depth + 1.0) return pages def lastmod(self, obj): @@ -86,7 +94,10 @@ def priority(self, obj): the site. Top level get highest priority, then each level is decreased by per_level. """ - prio = 1.0 - (obj.level + 1) * self.per_level + if getattr(obj, 'override_url', '') == '/': + prio = 1.0 + else: + prio = 1.0 - (obj.level + 1) * self.per_level # If the page is in_navigation, then it's more important, so boost # its importance From 22e7c167ee9234c2e324814b8870ed185abfd4de Mon Sep 17 00:00:00 2001 From: Psyton <psyton@vipbox.org> Date: Sun, 8 Jul 2012 15:54:20 +0700 Subject: [PATCH 0490/1590] Fixed pages order in sitemap --- feincms/module/page/sitemap.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index 2ed59a392..bda5f2b16 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -71,12 +71,14 @@ def items(self): if self.depth_cutoff > 0 and page.level == self.max_depth: continue if getattr(page, 'navigation_extension', None): + cnt = 0 for p in page.extended_navigation(): depth_too_deep = self.depth_cutoff > 0 and p.level > self.depth_cutoff not_in_nav = self.navigation_only and not p.in_navigation if depth_too_deep or not_in_nav: continue - pages.insert(idx + 1, p) + cnt += 1 + pages.insert(idx + cnt, p) if p.level > self.max_depth: self.max_depth = p.level From 3230f5f39243499e42eb5608372c2023db98b116 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 9 Jul 2012 15:45:12 +1000 Subject: [PATCH 0491/1590] Avoid explicit references to Page in PageAdmin --- feincms/module/page/modeladmins.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index b3c00daf5..6c7851f50 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -17,7 +17,6 @@ # ------------------------------------------------------------------------ from .forms import PageAdminForm -from .models import Page # ------------------------------------------------------------------------ class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): @@ -63,13 +62,14 @@ def add_extension_options(cls, *f): else: # assume called with "other" fields cls.fieldsets[1][1]['fields'].extend(f) - def __init__(self, *args, **kwargs): + def __init__(self, model, admin_site): ensure_completely_loaded() - if len(Page._feincms_templates) > 4 and 'template_key' in self.radio_fields: + if len(model._feincms_templates) > 4 and \ + 'template_key' in self.radio_fields: del(self.radio_fields['template_key']) - super(PageAdmin, self).__init__(*args, **kwargs) + super(PageAdmin, self).__init__(model, admin_site) # The use of fieldsets makes only fields explicitly listed in there # actually appear in the admin form. However, extensions should not be From a38ffd79cfffa7a58b190d2aecfd7e54ac3c22e1 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Wed, 11 Jul 2012 16:34:42 +1000 Subject: [PATCH 0492/1590] Allow FEINCMS_USE_PAGE_ADMIN=False to avoid registering default Page admin. --- feincms/module/page/admin.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index cb2ab5b0c..f5d9426b5 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -4,6 +4,7 @@ from __future__ import absolute_import +from django.conf import settings from django.contrib import admin from django.core.exceptions import ImproperlyConfigured from django.db.models import FieldDoesNotExist @@ -13,15 +14,20 @@ from .modeladmins import PageAdmin # ------------------------------------------------------------------------ -ensure_completely_loaded() -try: - Page._meta.get_field('template_key') -except FieldDoesNotExist: - raise ImproperlyConfigured( - 'The page module requires a \'Page.register_templates()\' call somewhere' - ' (\'Page.register_regions()\' is not sufficient).') -admin.site.register(Page, PageAdmin) +if getattr(settings, 'FEINCMS_USE_PAGE_ADMIN', True): + ensure_completely_loaded() + try: + Page._meta.get_field('template_key') + except FieldDoesNotExist: + raise ImproperlyConfigured( + "The page module requires a 'Page.register_templates()' call " + "somewhere ('Page.register_regions()' is not sufficient). " + "If you're not using the default Page admin, maybe try " + "FEINCMS_USE_PAGE_ADMIN=False to avoid this warning." + ) + + admin.site.register(Page, PageAdmin) # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ From 37536eeb34ff9edb9d74a78c9abad1209e5d901d Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Wed, 11 Jul 2012 16:35:36 +1000 Subject: [PATCH 0493/1590] Allow feincms_nav to work with non-default Page models. -- unless no feincms_page in context; need to figure out best way to handle that. Maybe an additional argument? --- feincms/module/page/templatetags/feincms_page_tags.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 2b59c869f..be0d31a4e 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -28,6 +28,7 @@ def feincms_nav(context, feincms_page, level=1, depth=1): if isinstance(feincms_page, HttpRequest): try: + # warning: explicit Page reference here feincms_page = Page.objects.for_request( feincms_page, best_match=True) except Page.DoesNotExist: @@ -38,10 +39,12 @@ def feincms_nav(context, feincms_page, level=1, depth=1): # mptt starts counting at zero mptt_level_range = [level - 1, level + depth - 1] - queryset = Page.objects.in_navigation().filter(**{ - '%s__gte' % mptt_opts.level_attr: mptt_level_range[0], - '%s__lt' % mptt_opts.level_attr: mptt_level_range[1], - }) + queryset = feincms_page.__class__._default_manager.in_navigation().filter( + **{ + '%s__gte' % mptt_opts.level_attr: mptt_level_range[0], + '%s__lt' % mptt_opts.level_attr: mptt_level_range[1], + } + ) page_level = getattr(feincms_page, mptt_opts.level_attr) From 4d1908f8916ff18ee8e845bf9f4fdffb4a57a198 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Wed, 11 Jul 2012 16:36:38 +1000 Subject: [PATCH 0494/1590] Remove explicit use of page.Page in views; customise via page_model_path arg. -- needs docs. --- feincms/views/cbv/views.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 7e8f1680c..5f23fe129 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -1,16 +1,24 @@ +from django.db.models import get_model from django.http import Http404 from feincms import settings from feincms.module.mixins import ContentView -from feincms.module.page.models import Page class Handler(ContentView): + page_model_path = 'page.Page' context_object_name = 'feincms_page' + @property + def page_model(self): + if not hasattr(self, '_page_model'): + self._page_model = get_model(*self.page_model_path.split('.')) + return self._page_model + def get_object(self): - return Page.objects.for_request(self.request, raise404=True, + return self.page_model._default_manager.for_request( + self.request, raise404=True, best_match=True, setup=False) def dispatch(self, request, *args, **kwargs): From bb483d999006df974e9230165b9fe4d83557bc90 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Wed, 11 Jul 2012 22:41:07 +1000 Subject: [PATCH 0495/1590] Decouple PageAdminForm from The One Page model. See #241. --- feincms/module/page/forms.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index d0f232867..0f32f0eba 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -13,8 +13,6 @@ from feincms import ensure_completely_loaded -from .models import Page, PageManager - from mptt.forms import MPTTAdminForm @@ -23,6 +21,14 @@ class PageAdminForm(MPTTAdminForm): never_copy_fields = ('title', 'slug', 'parent', 'active', 'override_url', 'translation_of', '_content_title', '_page_title') + @property + def page_model(self): + return self._meta.model + + @property + def page_manager(self): + return self.page_model._default_manager + def __init__(self, *args, **kwargs): ensure_completely_loaded() @@ -30,10 +36,11 @@ def __init__(self, *args, **kwargs): if 'parent' in kwargs['initial']: # Prefill a few form values from the parent page try: - page = Page.objects.get(pk=kwargs['initial']['parent']) + page = self.page_manager.get( + pk=kwargs['initial']['parent']) data = model_to_dict(page) - for field in PageManager.exclude_from_copy: + for field in self.page_manager.exclude_from_copy: if field in data: del data[field] @@ -44,13 +51,14 @@ def __init__(self, *args, **kwargs): data.update(kwargs['initial']) kwargs['initial'] = data - except Page.DoesNotExist: + except self.page_model.DoesNotExist: pass elif 'translation_of' in kwargs['initial']: # Only if translation extension is active try: - page = Page.objects.get(pk=kwargs['initial']['translation_of']) + page = self.page_manager.get( + pk=kwargs['initial']['translation_of']) original = page.original_translation data = { @@ -63,13 +71,13 @@ def __init__(self, *args, **kwargs): if original.parent: try: data['parent'] = original.parent.get_translation(kwargs['initial']['language']).id - except Page.DoesNotExist: + except self.page_model.DoesNotExist: # ignore this -- the translation does not exist pass data.update(kwargs['initial']) kwargs['initial'] = data - except (AttributeError, Page.DoesNotExist): + except (AttributeError, self.page_model.DoesNotExist): pass super(PageAdminForm, self).__init__(*args, **kwargs) @@ -96,7 +104,7 @@ def clean(self): current_id = None # See the comment below on why we do not use Page.objects.active(), # at least for now. - active_pages = Page.objects.filter(active=True) + active_pages = self.page_manager.filter(active=True) if self.instance: current_id = self.instance.id @@ -122,7 +130,7 @@ def clean(self): if current_id: # We are editing an existing page - parent = Page.objects.get(pk=current_id).parent + parent = self.page_manager.get(pk=current_id).parent else: # The user tries to create a new page parent = cleaned_data['parent'] From 6249526517a94c41b4204b72d605ca1b50c3103a Mon Sep 17 00:00:00 2001 From: Piet Delport <pjdelport@gmail.com> Date: Thu, 19 Jul 2012 23:58:09 +0200 Subject: [PATCH 0496/1590] Docs: fix typos. --- README.rst | 2 +- docs/admin.rst | 6 +++--- docs/advanced/designdecisions.rst | 10 +++++----- docs/page.rst | 10 +++++----- docs/releases/1.2.rst | 2 +- docs/releases/1.4.rst | 2 +- docs/templatetags.rst | 2 +- docs/versioning.rst | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index 4ea3407c4..75ce0cf94 100644 --- a/README.rst +++ b/README.rst @@ -74,7 +74,7 @@ Visit these sites * FeinCMS Website: http://www.feincms.org/ * Read the documentation: http://feincms-django-cms.readthedocs.org/ -* See the google groups page at http://groups.google.com/group/django-feincms +* See the Google Groups page at http://groups.google.com/group/django-feincms * FeinCMS on github: https://github.com/feincms/feincms/ IRC diff --git a/docs/admin.rst b/docs/admin.rst index 243c3e909..4c59146cd 100644 --- a/docs/admin.rst +++ b/docs/admin.rst @@ -95,7 +95,7 @@ The tabbed interface below is used to edit content and other properties of the edited object. A tab is shown for every region of the template or element, depending on whether templates are activated for the object in question [#f1]_. -Here's an screenshot of a content editing pane. The media file content is +Here's a screenshot of a content editing pane. The media file content is collapsed currently. New items can be added using the control bar at the bottom, and all content blocks can be reordered using drag and drop: @@ -153,7 +153,7 @@ settings on the content type model itself: * ``feincms_item_editor_includes``: - If you need additional Javascript or CSS files or need to perform additional + If you need additional JavaScript or CSS files or need to perform additional initialization on your content type forms, you can specify template fragments which are included in predefined places into the item editor. @@ -178,7 +178,7 @@ settings on the content type model itself: editors such as TinyMCE react badly to being dragged around - they are still visible, but the content disappears and nothing is clickable anymore. Because of this you might want to run routines before and after moving content types - around. This is achieved by adding your javascript functions to + around. This is achieved by adding your JavaScript functions to the ``contentblock_move_handlers.poorify`` array for handlers to be executed before moving and ``contentblock_move_handlers.richify`` for handlers to be executed after moving. Please note that the item editor executes all handlers diff --git a/docs/advanced/designdecisions.rst b/docs/advanced/designdecisions.rst index 272eb58af..164bc9d63 100644 --- a/docs/advanced/designdecisions.rst +++ b/docs/advanced/designdecisions.rst @@ -14,15 +14,15 @@ struggling with rich text editors for a long time. To be honest, I do not think it was a good idea to add that many features to the rich text editor. Resizing images uploaded into a rich text editor is a real pain, and what if you'd like to reuse these images or display -them using a lightbox script or something similar? You have to ressort -to writing loads of javascript code which will only work on one +them using a lightbox script or something similar? You have to resort +to writing loads of JavaScript code which will only work on one browser. You cannot really filter the HTML code generated by the user to kick out ugly HTML code generated by copy-pasting from word. The user will upload 10mb JPEGs and resize them to 50x50 pixels by himself. All of this convinced me that offering the user a rich text editor -with too much capabilites is a really bad idea. The rich text editor +with too much capabilities is a really bad idea. The rich text editor in FeinCMS only has bold, italic, bullets, link and headlines activated (and the HTML code button, because that's sort of inevitable -- sometimes the rich text editor messes up and you cannot fix it @@ -47,12 +47,12 @@ for images or something...). A page's content could look like this: * Rich Text * Floated image * Rich Text -* Youtube Video Link, embedding code is automatically generated from the link +* YouTube Video Link, embedding code is automatically generated from the link * Rich Text It's of course easier for the user to start with only a single rich text field, but I think that the user already has too much confusing -possibilites with an enhanced rich text editor. Once the user grasps +possibilities with an enhanced rich text editor. Once the user grasps the concept of content blocks which can be freely added, removed and reordered using drag/drop, I'd say it's much easier to administer the content of a webpage. Plus, the content blocks can have their own diff --git a/docs/page.rst b/docs/page.rst index 4bd580bf4..53b9f3b0a 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -224,7 +224,7 @@ The following extensions are available currently: Adds additional title fields to the page model. You may not only define a single title for the page to be used in the navigation, the <title> tag and inside the content area, you are not only allowed to define different titles - for the three uses but also enabld to define titles and subtitles for the + for the three uses but also enabled to define titles and subtitles for the content area. @@ -283,12 +283,12 @@ if the ``redirect_to`` page field is filled in). Using page response processors ============================== -Analogous to a request processor, a reponse processor runs after a page +Analogous to a request processor, a response processor runs after a page has been rendered. It needs to accept the page, the request and the response as parameters and may change the response (or throw an exception, but try not to). -A reponse processor is the right place to tweak the returned http response +A response processor is the right place to tweak the returned http response for whatever purposes you have in mind. :: @@ -309,7 +309,7 @@ TinyMCE is configured by default to only allow for minimal formatting. This has to be the best compromise between letting the client format text without destroying the page design concept. You can customize the TinyMCE settings by creating your own init_richtext.html that inherits from `admin/content/richtext/init_tinymce.html`. -You can even set your own css and linklist files like so:: +You can even set your own CSS and linklist files like so:: FEINCMS_RICHTEXT_INIT_CONTEXT = { 'TINYMCE_JS_URL': STATIC_URL + 'your_custom_path/tiny_mce.js', @@ -378,7 +378,7 @@ The following parameters can be used to modify the behaviour of the sitemap: in the site map. * ``max_depth`` -- if set to a non-negative integer, will limit the sitemap generated to this page hierarchy depth. -* ``changefreq`` -- should be a string or callable specifiying the page update frequency, +* ``changefreq`` -- should be a string or callable specifying the page update frequency, according to the sitemap protocol. * ``queryset`` -- pass in a query set to restrict the Pages to include in the site map. diff --git a/docs/releases/1.2.rst b/docs/releases/1.2.rst index 283a596f2..66b782905 100644 --- a/docs/releases/1.2.rst +++ b/docs/releases/1.2.rst @@ -31,7 +31,7 @@ FeinCMS 1.2 sports several large changes, including: * A new content type, ``TemplateContent`` has been added which can be used to render templates residing on the hard disk. -* The ``TreeEditor`` javascript code has been rewritten, reintroducing +* The ``TreeEditor`` JavaScript code has been rewritten, reintroducing drag-drop for reordering pages, but this time in a well-performing way not sluggish as before. diff --git a/docs/releases/1.4.rst b/docs/releases/1.4.rst index 58fc0f4fb..b44a41b6c 100644 --- a/docs/releases/1.4.rst +++ b/docs/releases/1.4.rst @@ -62,7 +62,7 @@ Apart from all these new features a few cleanups have been made: library have a look at ``MediaFile.reconfigure``. * Support for the ``show_on_top`` option for the ``ItemEditor`` has been - completely removed. This functionatliy has been deprecated since 1.2. + completely removed. This functionality has been deprecated since 1.2. * A few one-line Page manager methods which were too similar to each other have been deprecated. They will be removed in the next release of FeinCMS. diff --git a/docs/templatetags.rst b/docs/templatetags.rst index 3a50a725e..21c0737e2 100644 --- a/docs/templatetags.rst +++ b/docs/templatetags.rst @@ -91,7 +91,7 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: .. function:: siblings_along_path_to: - This is a filter designed to work in close conjuction with the + This is a filter designed to work in close conjunction with the ``feincms_navigation`` template tag describe above to build a navigation tree following the path to the current page. diff --git a/docs/versioning.rst b/docs/versioning.rst index df2f34a2a..a10cf19bf 100644 --- a/docs/versioning.rst +++ b/docs/versioning.rst @@ -30,7 +30,7 @@ FeinCMS' ``PageAdmin`` and from reversions ``VersionAdmin``:: admin.site.register(Page, VersionedPageAdmin) The ``VersionedPageAdmin`` does not look like the ItemEditor -- it's -just raw Django inlines, without any additional javascript. Patches are +just raw Django inlines, without any additional JavaScript. Patches are welcome, but the basic functionality needed for versioning page content is there. From d404b91cc7af75c343c78fe44273a8cff8aa5663 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 20 Jul 2012 08:51:08 +0200 Subject: [PATCH 0497/1590] Add a note concerning FEINCMS_USE_PAGE_ADMIN --- feincms/module/page/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index f5d9426b5..c22942200 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -15,6 +15,7 @@ # ------------------------------------------------------------------------ +# XXX move this setting to feincms.settings? if getattr(settings, 'FEINCMS_USE_PAGE_ADMIN', True): ensure_completely_loaded() try: From e2666ed479e84c208ce93f7fff5eeac3df983a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Ba=CC=88chler?= <sb@feinheit.ch> Date: Tue, 14 Aug 2012 16:22:18 +0200 Subject: [PATCH 0498/1590] except ValueError on siblings_along_path due to page pretenders --- feincms/module/page/templatetags/feincms_page_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 83b49f9af..5988b30f8 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -444,7 +444,7 @@ def siblings_along_path_to(page_list, page2): a_page.level == top_level or any((_is_sibling_of(a_page, a) for a in ancestors))] return siblings - except AttributeError: + except (AttributeError, ValueError): pass return () From 5c39d04bf5c0dad4514e6fb4db953831ddfc9a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Ba=CC=88chler?= <sb@feinheit.ch> Date: Tue, 14 Aug 2012 18:20:42 +0200 Subject: [PATCH 0499/1590] get navigation extension working again --- feincms/module/page/extensions/navigation.py | 6 ++++++ feincms/module/page/templatetags/feincms_page_tags.py | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 88ccbd4e9..caae94f00 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -36,6 +36,8 @@ class PagePretender(object): parameters on creation: title, url, level. If using the translation extension, also add language. """ + pk = None + # emulate mptt properties to get the template tags working class _mptt_meta: level_attr = 'level' @@ -62,6 +64,10 @@ def available_translations(self): def get_original_translation(self, page): return page + def short_title(self): + from feincms.utils import shorten_string + return shorten_string(self.title) + class NavigationExtension(object): """ diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 5988b30f8..99d03af48 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -66,8 +66,9 @@ def feincms_nav(context, feincms_page, level=1, depth=1): if parent: # Special case for navigation extensions if getattr(parent, 'navigation_extension', None): - return parent.extended_navigation(depth=depth, - request=context.get('request')) + return list(parent.extended_navigation(depth=depth, + request=context.get('request'))) + queryset &= parent.get_descendants() if depth > 1: @@ -86,7 +87,8 @@ def _filter(iterable): queryset = _filter(queryset) - if 'navigation' in feincms_page._feincms_extensions: + if any((ext in feincms_page._feincms_extensions for ext in ( + 'navigation', 'feincms.module.page.extensions.navigation'))): # Filter out children of nodes which have a navigation extension extended_node_rght = [] # mptt node right value From e506c0cfdea56f99c05394b9367255146d39031e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 15 Aug 2012 13:05:00 +0200 Subject: [PATCH 0500/1590] Add a few alters_data attributes here and there --- feincms/content/application/models.py | 2 ++ feincms/content/richtext/models.py | 1 + feincms/content/rss/models.py | 2 +- feincms/content/section/models.py | 1 + feincms/content/table/models.py | 1 + feincms/module/blog/models.py | 1 + feincms/module/medialibrary/models.py | 2 ++ feincms/module/page/models.py | 1 + feincms/translations.py | 2 ++ 9 files changed, 12 insertions(+), 1 deletion(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 982889944..2f8b8b9fe 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -452,11 +452,13 @@ def save(self, *args, **kwargs): super(ApplicationContent, self).save(*args, **kwargs) # Clear reverse() cache _empty_reverse_cache() + save.alters_data = True def delete(self, *args, **kwargs): super(ApplicationContent, self).delete(*args, **kwargs) # Clear reverse() cache _empty_reverse_cache() + delete.alters_data = True def _update_response_headers(self, request, response, headers): """ diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 11c06f1c4..4a123cc4b 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -102,6 +102,7 @@ def save(self, *args, **kwargs): self.text = self.cleanse.im_func(self.text) super(RichTextContent, self).save(*args, **kwargs) + save.alters_data = True @classmethod def initialize_type(cls, cleanse=False): diff --git a/feincms/content/rss/models.py b/feincms/content/rss/models.py index bf810f97a..196e5e1d3 100644 --- a/feincms/content/rss/models.py +++ b/feincms/content/rss/models.py @@ -49,4 +49,4 @@ def cache_content(self, date_format=None, save=True): if save: self.save() - + cache_content.alters_data = True diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index ff388ef6f..b7646116a 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -102,3 +102,4 @@ def save(self, *args, **kwargs): self.richtext = self.cleanse.im_func(self.text) super(SectionContent, self).save(*args, **kwargs) + save.alters_data = True diff --git a/feincms/content/table/models.py b/feincms/content/table/models.py index d06a2d957..fb7a617ce 100644 --- a/feincms/content/table/models.py +++ b/feincms/content/table/models.py @@ -95,3 +95,4 @@ def save(self, *args, **kwargs): self.html = self.data and self.FORMATTERS[self.type](json.loads(self.data)) or u'' super(TableContent, self).save(*args, **kwargs) + save.alters_data = True diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index cb01cf34f..dd699581c 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -48,6 +48,7 @@ def save(self, *args, **kwargs): if self.published and not self.published_on: self.published_on = timezone.now() super(Entry, self).save(*args, **kwargs) + save.alters_data = True @models.permalink def get_absolute_url(self): diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 8558ec957..03bca576b 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -62,6 +62,7 @@ def save(self, *args, **kwargs): self.slug = slugify(self.title) super(Category, self).save(*args, **kwargs) + save.alters_data = True def path_list(self): if self.parent is None: @@ -185,6 +186,7 @@ def save(self, *args, **kwargs): self.delete_mediafile(self._original_file_name) self.purge_translation_cache() + save.alters_data = True def delete_mediafile(self, name=None): if name is None: diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 4be2a8a29..eaddcfb5f 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -251,6 +251,7 @@ def save(self, *args, **kwargs): cached_page_urls[page.id] = page._cached_url super(Page, page).save() # do not recurse + save.alters_data = True @models.permalink def get_absolute_url(self): diff --git a/feincms/translations.py b/feincms/translations.py index b62b8988e..82bcbcd85 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -269,10 +269,12 @@ def short_language_code(self): def save(self, *args, **kwargs): super(Inner, self).save(*args, **kwargs) self.parent.purge_translation_cache() + save.alters_data = True def delete(self, *args, **kwargs): super(Inner, self).delete(*args, **kwargs) self.parent.purge_translation_cache() + delete.alters_data = True return Inner From e5a0dcb2d52e68e858db39c59ceb3aca4fc239d7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 16 Aug 2012 14:57:47 +0200 Subject: [PATCH 0501/1590] Make json imports 2.5-compatible again --- feincms/admin/tree_editor.py | 5 ++++- feincms/content/table/models.py | 5 ++++- feincms/contrib/fields.py | 5 ++++- feincms/module/medialibrary/zip.py | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 12e7ff3db..7d4256dfa 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -2,7 +2,10 @@ # coding=utf-8 # ------------------------------------------------------------------------ -import json +try: + import json +except ImportError: + from django.utils import simplejson as json # Python 2.5 import logging from django.conf import settings as django_settings diff --git a/feincms/content/table/models.py b/feincms/content/table/models.py index fb7a617ce..6fde427e2 100644 --- a/feincms/content/table/models.py +++ b/feincms/content/table/models.py @@ -1,4 +1,7 @@ -import json +try: + import json +except ImportError: + from django.utils import simplejson as json # Python 2.5 from django.db import models from django.utils.safestring import mark_safe diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index fea195bac..b8aa2427b 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -1,4 +1,7 @@ -import json +try: + import json +except ImportError: + from django.utils import simplejson as json # Python 2.5 import logging from django import forms diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 28b1712af..12ea15048 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -9,7 +9,10 @@ from __future__ import absolute_import -import json +try: + import json +except ImportError: + from django.utils import simplejson as json # Python 2.5 import zipfile import os import time From 4fc4c5b137702819c64ea4df89f7d43bc64a3358 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 16 Aug 2012 17:59:29 +0200 Subject: [PATCH 0502/1590] Update pt translation --- feincms/locale/pt/LC_MESSAGES/django.mo | Bin 14352 -> 15867 bytes feincms/locale/pt/LC_MESSAGES/django.po | 766 ++++++++++-------------- 2 files changed, 325 insertions(+), 441 deletions(-) diff --git a/feincms/locale/pt/LC_MESSAGES/django.mo b/feincms/locale/pt/LC_MESSAGES/django.mo index bc5942be3277c53673775cf825af87a424b02d07..e925141c9a6485796aacdcb5022833dd08907998 100644 GIT binary patch literal 15867 zcmbW73AkNVb;mc8KmZYh$|M|ym;~}}CPa9IAtOW+@=P93a0ut#d)|GA+<VUD3@>@9 z7*U+6I04R5Q&bux4n!@30``HTVo`CT6~WK;EBIBb{b;RK`}OzVd!Ku6CIQcv^?qmE z!`f@Fz4p5K>EZj{XgHogj+5+f%!0k(^SR)7@^E9WfKS0A;mcoW%(3taco=*gJO#cB z9t^j`ec*lYEO<Xux&H@M<grJ%?@xt#e>v3mYvG}ABis+Z4XT`X!Flj~{{H>&d0c<f z^SkgxT>ltOgTMCoe-CN0*_%c$g-5~=UJeg{Uxo+52cYVG7#;#2hkpTo3CG~RT&SG& zkXz>UkfO~E@Fj37R6o80UjQG2sL=ch9t8gz&VYN<NY#5PRQne|^>Y}i9p}RWz8vlg z?}aMoet-QCJelk7LVfpNQ04y~9s~D3%9zvPN${ocQmB4i2i4w>LFxZ?fBjW>G}k|b zYX7exLuCF4rH8|KcoRGUs(trBz4stI6aE0IAJ3<9-9Hj8h9^PkJA!Ketx)~G9jctW z;RoRZQ0;v!#-w_$hXK3=+Ipbc@dK!Oeh%rX`2|!tdt+46)4@>B4}%nGj)FAJEP!Xg zRq$2tTB!G*fcpMl{q=u%J`Gjx@1V+i-iwXN;2}_YdjnK|-VHSlAAl<FZh!wiILh^d zQ2l@L@y0BIb@*oZ2{;>`dV;g(OJR-cx5Ea!1I~xX1+*QmhO^+CpxUzyYTUm7)y})% z1@P-|Aw2X%*Z-AJdTK%0>t-lBxe==UTcFC@3e~UA`RDgSjl;K~?B#KY>6)jZ>OJTr z_x)i|^XzD-aXrOz2&!FYK#kiHsQO;%uP^g#LFvEr&o}$~Z-vt5jZp3Vu)qG4=cl3C z@j0k+zvOw3zyCFV{SZ|9z7N&D$Dzu75~|)`dj8gPF9y^04@xhG`Rk+n_3=>snGW^+ z0?%`x%D(`r-y=}<yvDN*)sB{D2Bpudp~mM1sD9oC<u~qts^=R}e)UIC<vj&89>0S7 zz<o|}<?atv|KU*e9}D+|Gok7og6h|qQ2jdBUoV6D?iEnwj{4^@R6Dx<{xwkjeLqzB zABSr1Hh+Dmzy2Cj`QL+j|52#=e-2guub{^3X{dVt0QZIaO?UUFLD}KqQ171zRo)D! z_i9kzEr4p@LMZ*L^3T`7{kU#I)qf>azY3^w-wxIO4?>mqNw_z>748SOLA7@~RK52= zmHz<z&|ZuK47t8)hAa0G$W%2?LXG1AGqDXAK#kvWsCJCP^WbY?0B?f026Hc*4IhJ= zZ_{QOa}GQn%06BV_k+3TBvkpEq1yLJfB!ak0N1xewc~E6em>&wKLK%-<|()s?sqC{ zHM|fW2p@oY|6wS-{sd~B`z2I6&1t*~j)!{Qg1WyE%CEd1svoyO>G@Hp{yYga-hY59 zZ(m+o1YZOXf|o%(kD&V5foe|<uZ36p=X(#i`_rJ-u_GWVGp9i5VHG?Cjzaab4&?`5 z56^~oLw)yKD0|qy=Gu82WQjAUL6x@@s@)xUBD@CbyPM(la63F0UNFbk2VcQ;9ZrLv zf$Ha-{{BO7HP=VYb<fA4#wquF9sCN{Z-#nr3BgSOuZO3=FTg|KqfmPOHz<Am5o%rA zk3~ZDo&a_KRH*XjL$&{G&(}b$)0<%f-T|ez;}*E@PWC(vYF;dWhr%<V-n$T92Uo-A z!^fcN`*(Ocd>U%}W^tkMn*&$Ev!L|z7B~XG2j2lteyLmcJ_}#Q_0Qn>@Msq40$vX3 zqIno<KJ3LyxIA+nRR0=K?P^2WQ4TMIo8kHJQHZIVW9T$Xtyv0n-GCau>!8Z{FjP4= z!^7aMQ009Y9t9tS((}*!_3xqjdBj<+|HnY-|0Jk>4?&gxGWa666snw8`{yM*g6qxj zaCn2ie~ahmq1tgbR6XB@YR@B3^*j#M-d}kB#^3)RsQ&CT?Amp(=Mhlf9S2p;45;@O zK(%Wjd?CCTz5vEh{n!LGzSlz4_fCI(J=FMr#9!a)pWp6zCzRj152~IYL6!Fels)|d zs{j8BPlAUsIW?~Hq3rt-sCKlW+I6+R|6VA&yalS=xB2S_pytOnq5Ah@DE<EnRQrDe zrRU#4wdY`*g7k4D)bjwUeKX-Pa6Z&~tDxF>2~_#(q28N>D*sLX{(GSMbrV!QpMfg( zt5EfP1M2<n`};qGD*q{{^8OR5Uw`n=_rlnv-vgoaeiT%BCqTVF!{46=rJpmQ^t}?w zUK&vE$548_3LXvL2-S~|Lh0#NsCvHyRqowT^*sPp?n6-JJOS0OC*fZ3mB`DH6xoXG zjWiMY6s>PNA581s@k!1WBiAELquy~RXFouu_wKlpEB*C958OvhCi2&}d49z6o$!97 zgItZg2azxN7NX-62mALXe?AL7h)748cV9tPA|FNOBeKc2B08ks3y{A<hLC?ibexae zj9i0Ui~KF}YUD0N$Cn-K-y8h-6YxXGWynd$Dr5@L5h8ckGyI@uh0k*GT4WvaUF16m zF47+N@^^thztvOtDe`S(Bk~D^sb|-k?eIs)Un4(6-jC>bJ@R3D=6vUJe=fY;pMP%P z9;RVlgM7o^yTWr5d>ir;e~n8v<A~<V8<6)RveC~V2O^InvNatsvJ6Rd!SPqf8stJm z^YRtQr;zKAV~`v<4$<)i<YV^C{rM-b4^kp?+%0n{T#Bqm-h~8+j(rjNZ5=C+4AFel zq4{vTJ#&BRpo?rnK98J*{0;ILQbTmiMvg_+BBvquAv(T?oQRx&EJ8LTI<_FMvS)5y zw>h7SoQnJ<@@eEH$N|VjNOfFXoxlyqKO!w;CUQ2S<9*0m?3w#B;?JkS@B8x!cq20D zuOEV6M=n7|kq;oxL*9XW75Nf!3!>wV$m@_Ly5N|B%tPL+3yzbKzegTH#t<D}MDDg{ z_-=SG@~FQ)%JYNpO~?!V^;Pfz<PhX*{@y+CAb<W%cslZ8<YDAo<lRVhd|W5fg54a` zXExGKCrXNSWgcZo*okK4K_14<AWee)!@R6_;$mGhEO@@Ko&|Hx-K97aES}_(vAA7C z*}5Vw+A7QR3u&ZfQgF-HnAgnoX29!F9>kq)niWygOwWVyFc0cclmwl0B5DRj8iYX- zZ3wz)9v5+%)XdBz4H{ur7qiTwW>dmT^(>CYf@otS%DP36mz_?S#hc=!6%^wUwI&7q z4AL<!<2>kwt*GX{Oj2IRX!}Hz)zds$=k#D7Hpb(2)4pskJ5e(ZeWPhv1BJBGY|=hc zBjY0K*o!=BM-6%u{HZT?C}9k>nMLikq}N&+8YeW4a?w?mcKVGE;<2C=PedqWQQ3@B zvp5<{v&bxtlaLlIF5ByavfEBW>E`kkBevDUW=Yr>r>u+DtmHIlL~Q{L1Wj68M6L(B z-kQyrG(wDo7Xquk%xg0&f_4<<Xf}xgr%7p{R+Y;rW*gLjU_)Gt2hDhFEVAEf=!0Ui z8wE4Nf-e{}6w-e^WJJ<-b6vDiR%1WbE!6C8&7uac{w3pK(u#uVx$$QzuFX@kByG3D zF3m2oNLR^NoT0>Y$L@OD@CuF?Z`(o)j{fFBSQcp~EaFDkZcp|Hq!x_2_GWRD3S?FF zXgr*V(=wYKgcxO>c6yeFLb8Y^(ULI9X&mNjmU3gL9_EZlx2(70d>nf<OQXDz#n!-O zuW<)kHA|V48mBU8Mp<5j3AU9^$h_kuFS4@XCdaZS1H|N2+l{>#tZ$i{9cJ0at_rY9 z;hf1A?ABtLi<{!EH662@)|VNRbh(}4W_dfz$IXSKt5yc1adXn0O@!?jH$mTmZk9I7 z20fDt(9~}R8^SE1#d$3lk<COw7EQ!V8%@x%EBDgunSMQLryEeHjN0Celag<TDXtUc zIV#C#<>o?E&!4=|EW8kPn-#4@U#Ljiwt*H^)tePoqbm}8ULof)Y*t_~-X<8fveBT5 zv6A7gnUzsE5e2eO#$Mioi=@aVgM2(KaSn{dWDuf$-cn<+_v#~S6Yfi%*w13QyTq2# z%@|qAX=A*lbw{h>MwaI3SP^KT+NOU!l5U8yku*+<ft#16S<_sE!L^*mnJH0{%dRd$ zsg<7%I<&7I$sifLi||^`<>P?4h?8zv*a3Fl#H_Z?Ftyf~o7MEjn>RWQvsP5dchrK# z5o(g2RYap*G6OK`e4Os#5u~Jg)QS@gcOX;qHzQ6_qH`i)&`z0CuE0^vpAhHJD40h$ z5?e^p@106vA(G?HXXqO`pypZUVn&uO51MJC)M92vcqgz+kVb@+A>F`G<3o~Wx}g@V zWt|H!ZTCifl7Sx!%XU%YLrr`$lH$*nI5nA(3|p{`$z=%jvM8`_XP)#viyHD-yg>Uo zk^bE(gFCEWNp~prnTp^$>;0ag5KR`dX6@QwEMh3DliaL{tY>OCH&{8p^8&Y2+Xclw zLct7~y1{^;&T3J#j&C7eBu!f9PM?|Mz#7rIi~&p&X4%3y{*jzvZ&~iY@9e_AKk$0( z&uLiiqk#qKJPLAJb~oiyP}$&Oy~Z}yO;g^M^LOjEw4*iytL0t4j2q*@D09cGMKNY= z6lRTa52h?e%s?_7I`JmwwAb3Ty|?(=5T)B~PY&~uR(%^T$YQX0?<1IgICnJ(v&($z zy!LC=XPPt}d?w2xzH=gOYVK4PZw=X+hbDmL&}3TTyC@PPY?OFF8tD99f6}Pzq-oZU z<KY`+k?U-OS*x{SZIN~ZEfCaV*4h9M^c|n`7X!|_AIYdjoH{C2@H2~f_$)s}DZ6|* z*=fhgdOuiZG;E>p7OY&2?RakmMtRMcDOXUb9kWpkdwqVQ8AW+Jn6tE*W-+DVVFuQ~ zet_9XyRlQB-ennJac|f)+F1@YaG!tyXFwZmD4;hxp&YmZ+}YMGj1gm`_?DJ^%g?d0 zZr@NdRY>oZz7`eJ5b9N)S*lU#y>+<K@31W)!v~GU5$g?euv#l~nY6kWvm_GcHN(kT zuqg0;z%Mh-%h|fpgf3FyM4ZQU%nVPZD#sP3ShEThh1z=w6T-R~Uzz$r&A43~5w+1% zbCMNdJ&`&dG)$@`P~|-1%Pvmzi{`)=>YIWgd2O|<6(w{~^QLdpC@S?8^k)}K305Q> zhME{fNiQj50>z~KZAR(rAg)EV;b6Qdy2EqkY}l}&=3lI_AkNtk7LD=qCeGQ^xpH3C z-L!Pg<#Sz+t3m2!QJ1;YHyFQYuz2*MHQ%gf{A7JJxq-FY`h@Bm8%sFzqYv$r+35#x zJVpojq)9U>qsz@D>JNWe<QYL5>0RngDQA7|O%}T-qy+iaR}jCVAe4HA4>hCa6_`rY zSYJ;!24Ni^Su>a6RGMirqhOk_*y;5oQZS@Ir5k0PIM)JaCo(fpD?MZ8);Uw{GT4OK zka8>}#BUO@<vTw@i#S4m-|hZ_!MBMy)nh^`BO{?gOI>PvnP3t@A(tKEc!|qxFg<Wy zxq`vx)jf)upkbjVz<^)KO`T|Dz41FsXx$s}T6H>Us>q3xq@ZE4)6NbTyzDj;6`iB# zU$NiOJKafK(|BRLzj0LLpdi@rCo}_gWe8gmBYm3)@6$F>qUJYY!LB#AoHTy#3w<1z zo3Scr*KW($Emxe3rS2?e!Ek5VhS@W|pi5z4+@{0+%?*awpMPBW9jRgH-5fSm49f}L z()%aVj>Zb3iD^3F#+uz*=BDof2Tlh^Vh^_mztnkwzw1vucf(IC9;a+Hy<s?=YEy6e zy}(ARU>VPEw6n6)qG6brY`9s26xP|;SDR%yDf`C{sIGHv*m#k>W}KKRLt$_gL)@nr z?7XrEU%G>f*X>vj-cWShzezCNH1@I1nCd1A71rBC#^8Bws#OsO$hi%7GKDpEj`YrW z&l+9M`iZR>&)nqgvSo-g6s?+k#}&Ddr5XD-2QB_oo9pVN*QT9s=v^kMU4h)+fKa@D z=7Z37*-6a6R3v;JyrdMFXW2E@k-NXv-@DTsxb@7&u|rbANS3NILo1p?m$;aGI9MLV z$&yuTr>%+PorYHBt++X~xNPM^qiJtlXpy8S>vl;P<NZb_pHmUnS4R1?k=3I^b}Nqx zhn6y3hlBZZ=gl9QyI^SUS;4$BhEIRlX>;ezoy&_u#GEv3r}xenS}-@5KX3S@^G=(~ zF>NJNW@yxB1=4IdxMXS@``KW5+$y6uo7x^MoEUTG>G>_qe>Lx1zH|G=q0uPp3<oP0 zU39_4i!N9eEL^$r{B~SRv(~xOR;^gItgnH2wYk%lIQtnIMW@5oK;~HUJzHTz#`<y2 z#iPrI&g{RZhLN%vT9!1JRN8@`S&xfe?ZZL0m^RWbi9?2#<2&-<AnDr6{G9n`2k!Ko znMrWsIl;VH)1E^fvWddA@wPFj%Ti*a&zy)HL3cYRBF%2|khssOEm@orrA;U3V8)>D zw8}?@%`{g=ax9H)s->9{BxPYxcF0Jk6QNB>PTewfb82ShG_xHMt~5jCB;y8y9+J;< zXJj`z>_Umwa69BD2~(~rmHi+~83x*sGpDESq5?b`eyuyTMRBY0lfI;Ym?l%~j87We z_Vi!y-&mh0-$RK5pZELLVWS&&rnV}PIrZ^s7ZZmAFVi`8^-Si0duV0%W!QMtb{BQ+ zsl**C>P~IX&1fq1t{&+7)YgE7rHR^iR>RaaHp97yKIKYq+CekRl8HFXq}r-w%5x4I z#i$HNLzzyW<YXvTkYmpCscjQcJBZrs<`^GTZ@c*?p3P>IS?2U@8504u(|{BMJ*C>F ziwJ2IsT9m0pa=a*@{|!LG*paEFFX38h`Z`szrn0hHXBM3ROxBf1?)<>l(L@VHp|%d zZ!i(+OWIu`ltEnO*F9!HP9~XH$@Y@vkd`YON-~r?4E>gDLg`}Mfl{J2=Nayzm^}?o z&qN918s6GwTifnp+ss;Jg|J;!byXQF_o<=6$2UtiV@8zjY=rhAPzE$?Qaw5)^vQh& z)IH?B4MVU-3RSAp-M4d5OI;QuQog3Cte$$COdV})sgmCcdZ|#gX0Q!58_HtgvZ1KD zuNIdS<%4Hw_lycH@D4;dQ?pF=!DMEl+l(m#u}jKyQQ)$ZzN4wjSlYztrnt0z&m~UD zg5`LrK(1{pWZ>`}6Va7B`VK;|lJx5)O&~N`595t&hcstoQSvdQP(#+2!3=6(RyXhn zH10y1MUBI@8FB6hZR35owkcJo3)c{px0{x`ylThT#475PAMvSGKjUbb?3V;9TMBk@ zOQU$BirN%gtHA;YXk`ga`AY3KLTx`78Rb{8I{9CGEfH4rF*>GmA+y_dn$@b260PP{ zQMpWjTnZWdUOu2UkVJj<nbu`CVw9=TeIm)I<;<6KVH15T!x(yhEmx@C+h4orlUrp- z%O>M^0aQ@k^Nzz#7PejkHbfmtU*Lr0`sq*F#Z0~!<<7q;Pa038wP2|<Wfu^+iZGaC z`<qN{!zTx{Q$==WqoLfYn4-`Zh0_i>N}GYL1<U$cZ1OV@`@AG%It=uZvgi(<%)p#z z4jyXAuQ^Hp4LCcq)aPN-fUK+;C7LO5n~Z9;M%iHugDV-_He;>vk~W)ZMsk*VSmR^v zhWK1O6L}F=1nXhX+f?3vNne*{NjuiEN|(tWYn*0WfW0@vY({@R*s4h&l^7Q$ZI@eI zNN$IfpL1*sjAcHDviMwC6I=2g%hTG$B&HhnWJL2MZ~G_S35PZ+z-wq`+l{U!opORW z?<$+ix{3Dn&w6)f6EZ&afZq|cfbvvovsU55ilCpa-E(?ZrEJ+D*6Dw>=Ok~h^;M&L z?(ENLIjVO{lI+jBjb4FTt!*;c58ux5kd~l!Ikl~slJ0HAQi+^PSh+Npe09-EnET9d z=2OFr;m+k5<rvdoP25P0w<T>Y8brI9S?!a;u61_!JE;P9W>>w;8=*_=sy2RZ=to+d zhc;`G`HZo9qnb=SR<4+#w~I=D5S2G}O~*cMs@Z*rg-mTHZR~<dmpYCTJh!Z5aGH8A z;1W8hQVnGq<b<kPHnjc?On8=18(^75Mc5uER$IldBI>tIACKUPZBN}gTfN)=t*^Hj z4hEck|ESJY>j3rcm`>ic6n=LYh+F%`SO>eua;k-_%`arlkfgFpF3a!HbuG^^&ccqI z-$7gb$~)uhY#wcD3wbkb5UeGb)%-65IjR$Ph+J`PTDE*((#tw4B2kiA3$m@G?*Z{Z zQ(HSj{LD+k@M~oJNma(IZlp`bi9@#b-JYH?oZYZp3s$?ez`n%bx>>I=_AZi!uGak) zzm;m?uSQ`<{rT?()i@ZT^F6;~I8zIU>1pM$)U3fMV?yg1Mm7;`qOK4hABVNzVpgG^ zb7BV4d*8YspW2S?lQbbGiRKlVam{u>bD|1gdb7P(ZPg!4QtOn)?@AmM<Huk9HZKJ; z@wEO`YmAE+p3N6_eck1|75t(?e!Ej=oYe0!9~j1gX+n<LMlAiTtIUV+#1>%V7}RZ> zCNmsx7OcP%xGECVG@rz)OIj=c8rZxwTaQ|_@wug}ZKckQ6DyO)qA(u<R_U^;1x>9O zzL|Ua!a5@BCc<_&K@>7Xl0cDJIQX@!n12c>8gT<ZMC{;_*2MlyJGXk1x3;}Cm!J+m z__#5xIHb~vHPzJK|Fp15WIg0(N^aZePyVSvP^*sUmsXqLbG@12vuMq91~0Q+@Nt#j zwqc?^cdY=*XSBWT+KH*uD((z}V%>Bh0CUo%vHg(IjA}Bu|4t*PSlZ<F@+$6E0^EPZ z>(+fwXB+1Kf75d)NE?W-LEjYb+1{r%m4+&O{+rm3<aTchW%|nm%GvD$y9*e6Qn@Ut zgj`EEC1{+8VwVU{N#5FYhN%+aA$e<JM}G2SOzB${!n%}k*|ssRhDJ@H%>+86gZ%y8 z7Q{a2HP%#)!K#aCqiBWvAmdh*<ZcaS%&k8qF4k7jzD0wq8E{8A1^hY|>F(IkwL2l3 zK4<lchHM6XJgmoU2A%5Yh-R?MqHCS-IU1-Gu^j{LOtB8To2$%#M7T|sI};qR57MOU zTgL6Y?!CP8*56c5s+4=`a_$`me(_)y4fq-3b0d{GxGjyDx=ZPtoxP`taw1_uLDTa& zCYidc6OlveOl{d1ck~m0OLq;ftV+99%h*7NcKeDon}JC&ut4|9-eK7p92k-){KUbM zHt1FCy=qj69s3j9B-mRu9$Hd%+<<ATMgMrvow`eTh16#86K@t;FCxETGJbvNTV8L; zs2(xn`rC}0U#Ik&8y4wJs%N~c%Trr@qTlYiDZtlWb;7$PZ;LMFfg3BPwz|ZAL-yD6 zUF=c@=5Zq{`&Yy{S=r0;+ojp<IDEQ4^X`FMzxNb`x(Zy3elEw(4at7j40j^OV$=TG zWD)LEohSaVu@VV?!cFD<0aK&U)=H@vpGxX$0Xy0Go}Ikaj{&Y_mA)}Z#WxI~pZflW w+(x^^<OiM%8Y4eJc+*tNHJPv;!X-I-<Cf9Bt*a1!&%ypg;BtRF8ge7>|H&Yp@c;k- delta 6554 zcmZ{ndw5jkoyXtEMdW575H3MDNVu8IkOYDlh*uEgQX-dBTTxDCPLhK&bA~f#5~3?Z zTiSXn+MZRsw7O`EqT;1lv|Ve92CbJ;+-|E|vE6EYT3y!e*6P!z+S>hm&m1KEqvy$Y zKJWXU_kDkt_cD`@uD&^6`qkLMw-}z6(G>KJp~j4_pgc;g#^lEsvl(uM<Ka(XHGCV^ zz`<jU842gcTnNviegPZ}uZi1lghQy`4hO-zVS_Oxb8r0O=MdZGXv{a^1nTd=;jp68 z7>Z^jTneW_8A`)p@Gf`?ybqoVAA^eFX;=l1zz+CZI1R2Dr};|8WGN`J9Z(M33TMG@ z!olzmRD>_UPr+B<$?$h@1pHqp2R?!tKbXlB=?Ex?#=rnpL(O+{%v<0L?3+6%XuuDk zCOiZu!<XR#cnmf{i!c;f8^o6BfJ*VzP!nGd<=9Q}``vI7^@pGWcn&Hf{{ioUZ@`jX z>>$sJ;8&p{cn+%lFw}&vK}Gl`R7A(%ZSVsq2X{?0hOC-?sBy1C8F~w9zW1Q^%%7pg zkH;%HJZ%#BSBDxJ6mcy)6J7`x!tL;L@Bq|+F?7-dRZw*c%HT|>c^aWIau%EcS3vd4 zKn1cDZic;ZDST}*`Tr7yX}DJhzYW=y=BF?T2XiD+a6W8=yWxEJB9y_8p_XpQX=O)7 zz~$5@!fkLfya@gR%Apxk%Z@CE8o#zgL2KRymBMzYwe5y1kGTQLz&%hA+z)jc9)((x zCu1Ih(UL)>{xzunZ^!lji}^8B21jxP^uAO@K?9~jrK%3fp@z8L67zg0N0vhkToZF+ z+`cKUr=T3X63W4DsCi3JhIhu?Rc6WDMj?tY=KWBqc^JyE15g9|V;+W@_*JNge+^~e z-I(t|Iq;{LCt2l8j)Lr0Qv(&?68I^d{}mKu=u*g~W;&rJ?1fs2?Qjqbp(fr9<-k2q z4m=3e|GQA{pMnbLd8j~s64!qYHSQ?Xyl=sw*f)Qspo_&!FTWTA74a-61NBfIx5V{} z;(8mDfp)0=F4V*YC`Yb^TpcEaa%dma(mev@$P=(6&kx2go`pI-hoJ_%4rSm?sDAH2 z4g5Wn!+(Ox*s#;f?<Yfzn+E03OelxuLCw1qDxmdH^KCwz{GUX@p+N(?pghk(8SaHL zume6_Va(T|O?^X6dE&<*%WPhPGvP6)r5r;=-xbr~Ij|9O0*w!K%5H{3;J0Rye-$2} zfj{#oA2R$390Gp{74dJNHqZY+MKE|)`9>Q9&!?V%YhfNL@`F(QUWCfjt56QT4duv3 za0Q%Hnq4;B4%P8ms1CQoXpLYU^@DIId>1N}??Xj0Xij-eC%`CTsJ+q{x1S9a$c0dj zt%f^cTl~Isl!CrgegpY4f8;}krpzs;at7owG!1YGTmu)w>!HRy2ernpKsj~{%HW4k zOKHyFHUuM}=C6Trd<|rL$=DQh3bsP6-5=m8_%}EluBt6Z)&@1uh1wI>#O*i1r>Nfp zwFH|<mjxe%n(yDCPQiac&G!M+RcsQfW4VUH$<*h;Vem}I#y01|MX){Qov@Mm&!94N za<V*bbj&KKj7)`kpM;}f6I=k7LS?2Go&rm7vm(Ea!YcUR@CLYWUinMt8K`f=_u;v) zuAZ|Ev#<fa0b5`t6*+z}l;O|95zvMkVHWzZA1;RriGuB8w!@MJ?xmoCk3bE49BR#; zfqe6tqjCKMs0c>SFGoHODy37PBAN|H!Um|*ayHaFZSi{#YOnOdv2fRX@~?q=;tmhO zG1L!08Tt{FLx-UZ{Q}C-w_+ZP+uwr<<gZXmIh1^hqoKxCLCrHAs$T+D!i5XSzX~g9 z(DAz*${`QRP%qR(JK$(|ZCu|SzrQ=?UZ}6@{ZIxDLCtd*YEQfh74h$&1wVw^W7Q>o z*vWwwC<iW%>+Ntn^=>#A-UyY-uf_ET;3(>kKt=WxRO(-Va`+V}gTI1u=nqht_%MDy zgr8S(ur!JSzlO{NsE&<r99#@#pcSg)<xmE?;`Sm`WM70b6hax^3uWkGI39ivYTOa1 zJ@GnJzxN^bO6D&VWMBweU6Gy&)nOb|%BMgrMQz;P2-UwiZeI#zXcer2Hq_qP1~t!i zsLXyDYBTSK3hXgBLg)X76lC}%sEJ>OGWZ(Q(!2pR(FahG{uNfhnMn7;z=xlM(PeZ! z%%cP7`{)w%Z|Gj+Aw3y1Ug!S;bSvsdO1+-1qWhv!d3h9(yvMfTI*6Vx@_7-eM-QT< z=mw<cDs(nFj6R3-%q=6j1LC47JsX$44u6Q00X>RbJ5-xX&tCK*(szNL`_WqT6~tyX z>rp4t6QX~OO2+(COns?sKr7MRaobL<|G!Wfgq}vL(2eLb=rI(aF0>I{i}dV4n^6<$ zMn!Zrnugd)pFC$#T8F-aw49$u1+*PGNKcE_U(Y^tTU0Wp2Yw5k8`p)cNSpC4qzmc@ z`Z2m3wW9~nL8NCE>O&W!hmoG)WtgAD6jJ(#?MG+3nfgmeKPb*Y$DbW>p$6WGzJ>;) z1X_%~jAo!K(U(vbeG`pBt!Nw43D9#ox(EF;dIpt##K-aH77D#+{_%#GjZjBxKl(!4 zHWogPZbmxa`fYF?(&MAqQHg)gV;;v76cqILkbNTl<FAd`MDY<c;Y5?MC_j%bL)V~7 z(Ua&V^jUNvIu%Vt!_dn}&&g;Fs#S&Ojxs*^TqalAsGfwjphwXU(7@*#ab*RpLmlWk zv<t09x1$_-2wj0*KzhE7z8jVJl?0RM5SkOWxo~$S9}Vb?xbf34%+Ib3D=W8zH&re; z#hN)MXJ?(cg|NT!oC&EeH<PyVcBf;`OQ)@z(_^`TlMTNzt|uHa{<22j$$H(66?C}; ztHWoU)x!wKa&rYY9k<)*tedk6PAYJ{Trzxe{1X$q+;rN>St&2yYk3{z;W83#sj3^4 zaf0x^szi9CYJPaegge8-6W$-W1}jD%R^WvPC$@xRChZTOpR_65Klv}=i`CVqWjs4= z);al%opK_7i6ii?@S~RS<LV{#b}n+=@^aX7tc=qUSdo)%ht=y9tsXlUFuUcX-GH9S zaP^dZ(*rMWEu+EBb(;0X_N*J2^}X4Qo4e8}rzO1gw8d@P0xRp}ipQr8e8;hT&kHO& zm$sr>&PzK5EAM;VN=szU4Z18lt+~CNow2e}50c^K9p6@CSUq)B-~CfxuLvKuoKgz^ zQ(bnhQ(1MaLf{uuLD6^0`J+)r+k36FZ+9lrzL(GAv*lzQJPQg*t2N`;1;@&HfhMqn zc(Q`k<7P5eJ2Tqd#N=kPB)|@wOmEUMmy(w*+AY6SPHozn$y{pA+P$n_j?5IDC}%P! z&vIT*!e*@*r6pzRjMtNlrqY-wz3Ru}yKxea_t7vfS1{$_#?I$6ZYs)!>3eDVg%y1h zXZ)<9&YF`V`)=U*bB*t&x~#z278C{)2XqMEt@+zYt`q)#W_8#wYr>-XMEzNbh9;}A zvAJnsZGA(1{qWYciFHo5TflN+DS<azjkF){H@~@l5&gm)vsO;d2Z`1V){^cHx3lQD zzISeC)^;<=l$Q;EIqS00C5a8bohxLRBc0e-ARo<EdJ8M&C48^o1c7bUC!3ND!!Jp+ zdI})1nwLd#)NHkSeo$oAf^*{SdavlGoC~^apTW&mG3ZDvI`Q@bub2z`UWTq+w_)S* z^Hzu6>^s8gbCwJ^!JFo+3SXEr^^}~~?Um21KQ|Y?GdI05&u+8Ihu6290<LAfOuFdX zmXq6B<Rowo3R*+o;-Ch;2h@vG+<#yHy{fW#IoHYX&>8!t6|=UL>hH_Dw&kUY89J7` z=ll0`x;Z=SsI4EiEaTGO_QMBj7li*=d(Mb;4w-XuX*=zO>AJn)xWti)bof?c`B)uv zKRWI{d&sxVvT*<6iQ&>@OL%W`UijOjO~;M%dKR?${reKEUD3|CSJ{zghN8B7xn`|f zzkXoL0jJQnqkdsUc(kErZp!w3r_=UzvI#aQy1r#wvCn^Ze^fWFNffi?`y=gH8C)hm zTZ@jL_UcHA<yl*cZh>rRU2Q)ZZg0F|Wue%fh-WJ#&9Yp#i>>nlJJaPAh>jyny_NWs z<mj5A9(QXkXU@vFop#y||2Tiers#^HqfQ+=-m`MH<=gI6R@%1u_xRl&mw}F7!OHdb zMVC$9^HaKA5*f}L7YwiLv>P>XUo%y7*F<RxcP>~P)->&^vaOBlR$E*8_h<v~8F*Pa z@O;yhfAs3Zrc!v-!e^&$=-(d{GlbUGzd!AGrj2yuJnq=QG5yztJI|aQK6GZ{{8nu} zI}>orDcxA{i(F)EnG<2KFgDvQr!<#uFpq2J)4IDzdYEsRUgD-A*LJ{n4(UjqSi@p; zMMYNP`>AXvT9^UrYj=7WjjkHJ$Xe~TyUk0QXkd922XxkDMH)`@8_6X_;@D3V`kq*n zubASW*w3bedr4P>adRD>pG}4<nwNw(HunrA_H6(DaKz&3<Hh9SDU-{sg!9S3XnE+_ z*R^<SMU%xn=MA{lOtb+CQFGz%Dg!!&zh06W&Smdp`Bn^^a8*l7C5D3XGO<-sUZ%+5 Jyt8HV{{xCNn1KKQ diff --git a/feincms/locale/pt/LC_MESSAGES/django.po b/feincms/locale/pt/LC_MESSAGES/django.po index a30612be0..19b859184 100644 --- a/feincms/locale/pt/LC_MESSAGES/django.po +++ b/feincms/locale/pt/LC_MESSAGES/django.po @@ -1,35 +1,33 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# +# +# Translators: +# <vfigueiro@gmail.com>, 2012. msgid "" msgstr "" -"Project-Id-Version: FienCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2010-09-15 23:08+0100\n" +"Project-Id-Version: FeinCMS\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2012-03-09 16:47+0100\n" +"PO-Revision-Date: 2012-06-30 21:51+0000\n" "Last-Translator: Vítor Figueiró <vfigueiro@gmail.com>\n" -"Language-Team: pt-PT <vfigueiro@gmail.com>\n" -"Language: \n" +"Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Translated-Using: django-rosetta 0.5.1\n" -"X-Poedit-Language: Portuguese\n" -"X-Poedit-SourceCharset: utf-8\n" -"X-Poedit-Country: PORTUGAL\n" +"Language: pt\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:419 content/template/models.py:59 msgid "template" msgstr "modelo" -#: models.py:553 +#: models.py:550 msgid "ordering" msgstr "ordenação" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:102 msgid "language" msgstr "idioma" @@ -37,48 +35,49 @@ msgstr "idioma" msgid "All" msgstr "Todos" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:57 module/page/models.py:143 msgid "Parent" msgstr "Ascendente" #: admin/filterspecs.py:95 +#: templates/admin/medialibrary/mediafile/change_list.html:15 msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:150 +#: admin/item_editor.py:163 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:214 content/rss/models.py:20 +#: content/section/models.py:31 module/blog/models.py:30 +#: module/medialibrary/models.py:43 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "título" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:389 #, python-format msgid "%s has been moved to a new position." msgstr "%s foi movido para uma nova posição" -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:393 msgid "Did not understand moving instruction." msgstr "A instrução para mover não foi entendida." -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:402 msgid "actions" msgstr "acções" -#: content/application/models.py:241 +#: content/application/models.py:264 msgid "application content" msgstr "conteúdo de aplicação" -#: content/application/models.py:242 +#: content/application/models.py:265 msgid "application contents" msgstr "conteúdos de aplicação" -#: content/application/models.py:273 +#: content/application/models.py:296 msgid "application" msgstr "aplicação" @@ -126,58 +125,74 @@ msgstr "formulário de contacto" msgid "contact forms" msgstr "formulários de contacto" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:86 msgid "file" msgstr "ficheiro" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "ficheiros" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "imagem" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "texto alternativo" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "Descrição da imagem" + +#: content/image/models.py:48 module/medialibrary/models.py:237 +msgid "caption" +msgstr "legenda" + +#: content/image/models.py:53 msgid "images" msgstr "imagens" -#: content/image/models.py:42 content/medialibrary/models.py:105 +#: content/image/models.py:79 content/medialibrary/models.py:105 #: content/medialibrary/models.py:113 msgid "position" msgstr "posição" +#: content/image/models.py:87 +msgid "format" +msgstr "formato" + #: content/medialibrary/models.py:38 msgid "(no caption)" msgstr "(sem legenda)" #: content/medialibrary/models.py:87 content/medialibrary/models.py:101 #: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/section/models.py:47 module/medialibrary/fields.py:45 +#: module/medialibrary/models.py:99 msgid "media file" -msgstr "ficheiro de mídia" +msgstr "ficheiro multimédia" #: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: module/medialibrary/models.py:100 msgid "media files" -msgstr "ficheiros de mídia" +msgstr "ficheiros multimédia" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:130 msgid "block" msgstr "bloco" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:131 msgid "left" msgstr "esquerda" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:132 msgid "right" msgstr "direita" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:49 content/section/models.py:52 +#: content/section/models.py:60 content/table/models.py:81 msgid "type" msgstr "tipo" @@ -190,7 +205,7 @@ msgid "raw contents" msgstr "conteúdos crus" #: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 +#: content/section/models.py:32 msgid "text" msgstr "texto" @@ -207,9 +222,7 @@ msgstr "Ignorar os avisos de validação do HTML" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo " -"actualizado em baixo antes de continuar: %(messages)s " +msgstr "A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo actualizado em baixo antes de continuar: %(messages)s " #: content/richtext/models.py:89 msgid "rich text" @@ -223,9 +236,7 @@ msgstr "textos ricos" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só " -"aparece no site após a actualização do feed RSS seguinte." +msgstr "O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só aparece no site após a actualização do feed RSS seguinte." #: content/rss/models.py:22 msgid "link" @@ -245,17 +256,17 @@ msgstr "número máximo" #: content/rss/models.py:29 msgid "RSS feed" -msgstr "alimentação RSS" +msgstr "feed RSS" #: content/rss/models.py:30 msgid "RSS feeds" -msgstr "alimentações RSS" +msgstr "feed RSS" -#: content/section/models.py:37 +#: content/section/models.py:36 msgid "section" msgstr "secção" -#: content/section/models.py:38 +#: content/section/models.py:37 msgid "sections" msgstr "secções" @@ -269,7 +280,7 @@ msgstr "linha de título" #: content/table/models.py:65 msgid "title row and column" -msgstr "linha de título e coluna" +msgstr "linha e coluna de título" #: content/table/models.py:71 msgid "table" @@ -283,57 +294,58 @@ msgstr "tabelas" msgid "data" msgstr "dados" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" -msgstr "conteúdo de template" +msgstr "conteúdo do modelo" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "conteúdos de template" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "ligação de vídeo" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Isto deve ser uma ligação par um vídeo do Youtube ou do vimeo, p.ex.: http://" -"www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "vídeo" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "vídeos" -#: module/blog/models.py:31 +#: contrib/tagging.py:113 +msgid "Tagging" +msgstr "Tagging" + +#: module/blog/models.py:29 msgid "published" msgstr "publicado" -#: module/blog/models.py:33 +#: module/blog/models.py:31 msgid "This is used for the generated navigation too." msgstr "Isto também é usado para a navegação gerada automaticamente." -#: module/blog/models.py:36 +#: module/blog/models.py:34 msgid "published on" msgstr "publicado em" -#: module/blog/models.py:37 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"É definido automaticamente quando activa a caixa de verificação 'publicado' " -"acima." +#: module/blog/models.py:35 +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Será definido automaticamente quando activar a caixa de verificação 'publicado' acima." -#: module/blog/models.py:42 +#: module/blog/models.py:40 msgid "entry" msgstr "entrada" -#: module/blog/models.py:43 +#: module/blog/models.py:41 msgid "entries" msgstr "entradas" @@ -342,39 +354,59 @@ msgid "tags" msgstr "etiquetas" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:105 msgid "translation of" msgstr "tradução de" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:108 msgid "Leave this empty for entries in the primary language." -msgstr "Deixe este campo em branco nas entradas do idioma original." +msgstr "Deixe este campo em branco nas entradas no idioma original." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "traduções disponíveis" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:36 msgid "creation date" msgstr "data de criação" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:37 msgid "modification date" msgstr "data de modificação" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "tipos de conteúdo" +#: module/extensions/datepublisher.py:48 +msgid "publication date" +msgstr "data de publicação" + +#: module/extensions/datepublisher.py:50 +msgid "publication end date" +msgstr "publicar até" + +#: module/extensions/datepublisher.py:52 +msgid "Leave empty if the entry should stay active forever." +msgstr "Deixe vazio se a entrada deve permanecer activa para sempre." + +#: module/extensions/datepublisher.py:79 +msgid "visible from - to" +msgstr "visível de - até" + +#: module/extensions/datepublisher.py:89 +msgid "Date-based publishing" +msgstr "Publicação baseada em datas" + #: module/extensions/featured.py:9 msgid "featured" -msgstr "recomendado" +msgstr "em destaque" #: module/extensions/featured.py:14 msgid "Featured" -msgstr "Recomendado" +msgstr "Em destaque" #: module/extensions/seo.py:9 msgid "meta keywords" @@ -396,232 +428,251 @@ msgstr "Isto será inserido antes da descrição padrão." msgid "Search engine optimization" msgstr "Optimização para motor de busca" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:175 +msgid "Edit translation" +msgstr "Editar a tradução" + +#: module/extensions/translations.py:178 +msgid "Create translation" +msgstr "Criar tradução" + +#: module/extensions/translations.py:183 +msgid "translations" +msgstr "traduções" + +#: module/medialibrary/forms.py:25 +msgid "This would create a loop in the hierarchy" +msgstr "Isto criaria um ciclo na hierarquia" + +#: module/medialibrary/forms.py:57 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "Não é possível sobrescrever com um tipo de ficheiro diferente (tentativa de substituir um %(old_ext)s com um %(new_ext)s)" + +#: module/medialibrary/modeladmins.py:58 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." +msgstr[1] "%(count)d ficheiros multimédia adicionados com sucesso a %(category)s." + +#: module/medialibrary/modeladmins.py:76 +msgid "Add selected media files to category" +msgstr "Adicionar os ficheiros multimédia seleccionados à categoria" + +#: module/medialibrary/modeladmins.py:85 +#, python-format +msgid "ZIP file exported as %s" +msgstr "Ficheiro ZIP exportado como %s" + +#: module/medialibrary/modeladmins.py:87 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "A exportação do ficheiro ZIP falhou: %s" + +#: module/medialibrary/modeladmins.py:92 +msgid "Export selected media files as zip file" +msgstr "Exportar os ficheiros multimédia seleccionados como ficheiro zip" + +#: module/medialibrary/modeladmins.py:141 +#: templates/admin/feincms/page/page/item_editor.html:14 +msgid "Preview" +msgstr "Antevisão" + +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:90 +msgid "file size" +msgstr "tamanho do ficheiro" + +#: module/medialibrary/modeladmins.py:151 module/medialibrary/models.py:88 +msgid "created" +msgstr "criado em" + +#: module/medialibrary/modeladmins.py:170 module/medialibrary/models.py:87 +msgid "file type" +msgstr "tipo de ficheiro" + +#: module/medialibrary/modeladmins.py:191 +msgid "file info" +msgstr "informação do ficheiro" + +#: module/medialibrary/modeladmins.py:203 +#, python-format +msgid "%d files imported" +msgstr "%d ficheiros importados" + +#: module/medialibrary/modeladmins.py:205 +#, python-format +msgid "ZIP import failed: %s" +msgstr "A importação do ficheiro ZIP falhou: %s" + +#: module/medialibrary/modeladmins.py:207 +msgid "No input file given" +msgstr "Não indicou o ficheiro de origem" + +#: module/medialibrary/models.py:46 msgid "parent" msgstr "ascendente" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:48 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:52 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:53 module/medialibrary/models.py:92 msgid "categories" msgstr "categorias" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "tipo de ficheiro" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "criado em" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:89 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "tamanho do ficheiro" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "inform. do ficheiro" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:209 msgid "Image" msgstr "Imagem" -#: module/medialibrary/models.py:281 +#: module/medialibrary/models.py:210 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:211 msgid "Audio" msgstr "Áudio" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:212 msgid "PDF document" -msgstr "documento PDF" +msgstr "Documento PDF" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:213 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:214 msgid "Text" msgstr "Texto" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:215 msgid "Rich Text" msgstr "Texto Rico" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:216 msgid "Zip archive" -msgstr "" +msgstr "Ficheiro zip" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:217 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:218 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:219 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:220 msgid "Binary" msgstr "Binário" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "legenda" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:238 msgid "description" msgstr "descrição" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:241 msgid "media file translation" -msgstr "tradução do ficheiro de mídia" +msgstr "tradução do ficheiro multimédia" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:242 msgid "media file translations" -msgstr "traduções do ficheiro de mídia" +msgstr "traduções do ficheiro multimédia" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Pré-visualização" +#: module/page/forms.py:113 +msgid "This URL is already taken by an active page." +msgstr "Este URL já está tomado por uma página activa." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:131 +msgid "This URL is already taken by another active page." +msgstr "Este URL já está tomado por uma outra página activa." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:40 +msgid "Other options" +msgstr "outras opções" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" -msgstr "" +#: module/page/modeladmins.py:88 module/page/models.py:145 +msgid "in navigation" +msgstr "na navegação" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" -msgstr "" +#: module/page/modeladmins.py:99 +msgid "Add child page" +msgstr "Adicionar página descendente" -#: module/medialibrary/models.py:448 -msgid "No input file given" -msgstr "" +#: module/page/modeladmins.py:101 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Ver no site" -#: module/page/models.py:256 -msgid "active" +#: module/page/modeladmins.py:129 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." +msgstr "O conteúdo da tradução original foi copiado para a página recém-criada." + +#: module/page/modeladmins.py:143 +msgid "You don't have the necessary permissions to edit this object" +msgstr "Não possui as permissões necessárias para editar este objecto" + +#: module/page/modeladmins.py:158 +msgid "inherited" +msgstr "herdado" + +#: module/page/modeladmins.py:162 +msgid "extensions" +msgstr "extensões" + +#: module/page/modeladmins.py:166 module/page/models.py:179 +msgid "is active" msgstr "activo" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "na navegação" +#: module/page/models.py:138 +msgid "active" +msgstr "activo" -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "URL efectivo" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"URL efectivo. Deve conter uma /, caso se trate de um URL local. Este campo " -"determina a navegação e os URL's das sub-páginas." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "URL efectivo. Deve conter uma / no início e no fim, caso se trate de um URL local. Este campo determina a navegação e os URL's das sub-páginas." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "redireccionar para" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "URL de destino para redireccionamentos automáticos." -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "URL em cache" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "página" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "páginas" -#: module/page/models.py:297 module/page/models.py:782 -msgid "is active" -msgstr "activo" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Esta URL já está tomada por uma página activa." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Esta URL já está tomada por uma outra página activa." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "outras opções" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Adicionar página descendente" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Ver no site" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "herdado" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "extensões" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "data de publicação" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "publicar até" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Deixe vazio se a entrada deve permanecer activa para sempre." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "visível de - até" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "Publicação baseada em datas" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "excerto" @@ -634,18 +685,18 @@ msgstr "Adicione um breve excerto que resuma o conteúdo desta página." msgid "Excerpt" msgstr "Excerto" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:74 +#: module/page/extensions/navigation.py:94 msgid "navigation extension" msgstr "extensão de navegação" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:96 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "Seleccione o módulo que providencia sub-páginas." +msgstr "Seleccione o módulo que providencia as sub-páginas, caso necessite de personalizar a navegação." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:109 msgid "Navigation extension" msgstr "Extensão de navegação" @@ -659,7 +710,7 @@ msgstr "Páginas relacionadas" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Site" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" @@ -679,8 +730,7 @@ msgstr "título do conteúdo" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" -"A primeira linha é o título principal. Outras linhas serão sub-títulos." +msgstr "A primeira linha é o título principal. Outras linhas serão sub-títulos." #: module/page/extensions/titles.py:15 msgid "page title" @@ -688,25 +738,12 @@ msgstr "título da página" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Título da página para a janela do navegador. Se omitido assume o título." +msgstr "Título da página para a janela do navegador. Se omitido assume o título." #: module/page/extensions/titles.py:43 msgid "Titles" msgstr "Títulos" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Editar a tradução" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Criar tradução" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "traduções" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -742,18 +779,15 @@ msgstr "Alterar o modelo" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." -msgstr "" -"Confirma a alteração do modelo? <br />Todas as alterações serão guardadas." +msgstr "Confirma a alteração do modelo? <br />Todas as alterações serão guardadas." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." -msgstr "" -"Confirma que deseja alterar o modelo? <br />Todas as alterações serão " -"guardadas e o conteúdo de <strong>%(source_regions)s</strong> será movido " -"para <strong>%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from " +"<strong>%(source_regions)s</strong> is moved to " +"<strong>%(target_region)s</strong>." +msgstr "Confirma que deseja alterar o modelo? <br />Todas as alterações serão guardadas e o conteúdo de <strong>%(source_regions)s</strong> será movido para <strong>%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -789,7 +823,16 @@ msgstr "O conteúdo é herdado da página ascendente, excepto se o indicar aqui. msgid "Add new item" msgstr "Adicionar novo item" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "Adicionar outro %(verbose_name)s" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "Remover" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Guardar" @@ -819,7 +862,7 @@ msgstr "remover" #: templates/admin/feincms/recover_form.html:7 #: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/page/page/item_editor.html:22 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Página inicial" @@ -827,38 +870,38 @@ msgstr "Página inicial" #: templates/admin/feincms/recover_form.html:10 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Recuperar %(verbose_name)s excluído" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Clique no botão 'Guardar' em baixo para recuperar esta versão do objecto." #: templates/admin/feincms/revision_form.html:14 msgid "History" -msgstr "" +msgstr "Historial" #: templates/admin/feincms/revision_form.html:15 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Reverter %(verbose_name)s" #: templates/admin/feincms/revision_form.html:28 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Clique no botão 'Guardar' em baixo para reverter para esta versão do objecto." -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Atalhos" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Colapsar a árvore" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Expandir a árvore" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filtrar" @@ -866,38 +909,40 @@ msgstr "Filtrar" msgid "Edit on site" msgstr "Editar no site" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:26 msgid "Add" -msgstr "" +msgstr "Adicionar" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "tradução do ficheiro de mídia" +msgstr "Adicionar ficheiros multimédia à categoria" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "" +msgstr "Seleccione a categoria a aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" +msgstr "Os seguintes ficheiros multimédia serão adicionados à categoria seleccionada:" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "categoria" +msgstr "Adicionar à categoria" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "Cancelar" #: templates/admin/medialibrary/mediafile/change_list.html:12 msgid "Bulk upload a ZIP file:" msgstr "Enviar um ficheiro ZIP:" -#: templates/admin/medialibrary/mediafile/change_list.html:21 +#: templates/admin/medialibrary/mediafile/change_list.html:22 +msgid "Overwrite" +msgstr "Sobrescrever" + +#: templates/admin/medialibrary/mediafile/change_list.html:25 msgid "Send" msgstr "Enviar" @@ -910,14 +955,9 @@ msgstr "%(comment_count)s comentários." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br /" -">\n" -" " -msgstr "" -"\n" -" %(comment_username)s disse em " -"%(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br />\n" " " +msgstr "\n %(comment_username)s disse em %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -934,159 +974,3 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Obrigado!" - -#~ msgid "rich text (ckeditor)" -#~ msgstr "texto rico (ckeditor)" - -#~ msgid "rich texts (ckeditor)" -#~ msgstr "textos ricos (ckeditor)" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Pode editar a página copiada em baixo." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Substituiu %s. Pode continuar a editar a página agora activa em baixo." - -#~ msgid "Move to" -#~ msgstr "Mover para" - -#~ msgid "Move" -#~ msgstr "Mover" - -#~ msgid "Add %(name)s" -#~ msgstr "Adicionar %(name)s" - -#~ msgid "Select an item on the left side if you want to edit it." -#~ msgstr "Seleccione um item do lado esquerdo, se o quiser editar." - -#~ msgid "" -#~ "You can change the structure of the tree by drag-dropping elements. " -#~ "Please note that changes will be saved immediately. " -#~ msgstr "" -#~ "Pode alterar a estrutura da árvore arrastando elementos. Note que as " -#~ "alterações serão guardadas imediatamente." - -#~ msgid "" -#~ "The context menu on the tree root and tree nodes provide you with " -#~ "additional modes of operation." -#~ msgstr "" -#~ "O menu de contexto na raiz da árvore e nos nós proporciona-lhe modos " -#~ "adicionais de operação." - -#~ msgid "Cannot remove this frame while inside this admin section." -#~ msgstr "" -#~ "Não pode remover esta moldura enquanto estiver dentro desta secção de " -#~ "admin." - -#~ msgid "Reload" -#~ msgstr "Recarregar" - -#~ msgid "Edit" -#~ msgstr "Editar" - -#~ msgid "Delete" -#~ msgstr "Eliminar" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Substituir a página %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Criar uma cópia oculta desta página" - -#~ msgid "Click save to replace the current content with this version" -#~ msgstr "Clique em guardar para substituir o conteúdo actual por esta versão" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "%(name)s \"%(obj)s\" foi modificado com sucesso." - -#~ msgid "You may edit it again below." -#~ msgstr "Pode voltar a editar o elemento." - -#~ msgid "You may add another %s below." -#~ msgstr "Pode adicionar um novo %s." - -#~ msgid "Cut" -#~ msgstr "Cortar" - -#~ msgid "Insert as child" -#~ msgstr "Inserir como descendente" - -#~ msgid "Insert before" -#~ msgstr "Inserir antes" - -#~ msgid "Video from unknown portal" -#~ msgstr "Vídeo de um portal desconhecido" - -#~ msgid "Tree saved successfully." -#~ msgstr "Árvore guardada com sucesso." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "Um nó não pode ser dependente de si próprio." - -#~ msgid "No item has been selected." -#~ msgstr "Não seleccionou nenhum item." - -#~ msgid "Add Child Page" -#~ msgstr "Adicionar Página Descendente" - -#~ msgid "Save and add another" -#~ msgstr "Guardar e adicionar outro" - -#~ msgid "Save and continue editing" -#~ msgstr "Guardar e continuar a editar" - -#~ msgid "Please correct the error below." -#~ msgid_plural "Please correct the errors below." -#~ msgstr[0] "Por favor corrija o erro em baixo." -#~ msgstr[1] "Por favor corrija os erros em baixo." - -#~ msgid "Properties" -#~ msgstr "Propriedades" - -#~ msgid "Move selected item to" -#~ msgstr "Mover item seleccionado para" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "is visible" -#~ msgstr "é visível" - -#~ msgid "Database error" -#~ msgstr "Erro de base de dados" - -#~ msgid "view content" -#~ msgstr "conteúdo da função" - -#~ msgid "" -#~ "Could not parse the view content because the view is excluded from " -#~ "infanta handling." -#~ msgstr "" -#~ "Não foi possível ler o conteúdo da vista, porque esta está excluída do " -#~ "tratamento de infanta." - -#~ msgid "Placeholder for the %(viewname)s calling %(viewfunc)s" -#~ msgstr "Substituto para %(viewname)s, que chama %(viewfunc)s" - -#~ msgid "Placeholder for calling %(viewfunc)s" -#~ msgstr "Substituto para chamar %(viewfunc)s" - -#~ msgid "not active" -#~ msgstr "inactivo" - -#~ msgid "Save tree" -#~ msgstr "Guardar árvore" - -#~ msgid "%(icon)s (not active)" -#~ msgstr "%(icon)s (inactivo)" - -#~ msgid "%(icon)s (until %(from)s)" -#~ msgstr "%(icon)s (até %(from)s)" - -#~ msgid "%(icon)s (since %(to)s)" -#~ msgstr "%(icon)s (a partir de %(to)s)" - -#~ msgid "%(icon)s (%(from)s – %(to)s)" -#~ msgstr "%(icon)s (%(from)s – %(to)s)" From d5752567a998daa4ed50e5027322da1c5f542080 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 16 Aug 2012 18:18:31 +0200 Subject: [PATCH 0503/1590] Regenerate locale files --- feincms/locale/ca/LC_MESSAGES/django.po | 712 +++++++-------- feincms/locale/cs/LC_MESSAGES/django.po | 560 ++++++------ feincms/locale/de/LC_MESSAGES/django.po | 317 +++---- feincms/locale/en/LC_MESSAGES/django.mo | Bin 0 -> 378 bytes feincms/locale/en/LC_MESSAGES/django.po | 305 +++---- feincms/locale/es/LC_MESSAGES/django.po | 713 +++++++-------- feincms/locale/fr/LC_MESSAGES/django.po | 770 +++++++--------- feincms/locale/hr/LC_MESSAGES/django.po | 710 +++++++-------- feincms/locale/it/LC_MESSAGES/django.po | 732 +++++++-------- feincms/locale/nb/LC_MESSAGES/django.po | 625 +++++++------ feincms/locale/nl/LC_MESSAGES/django.po | 650 +++++++------- feincms/locale/pl/LC_MESSAGES/django.po | 994 +++++++++++++++++++++ feincms/locale/pt/LC_MESSAGES/django.po | 397 ++++---- feincms/locale/pt_BR/LC_MESSAGES/django.po | 842 ++++++++--------- feincms/locale/ro/LC_MESSAGES/django.po | 808 ++++++++--------- feincms/locale/ru/LC_MESSAGES/django.po | 690 +++++++------- feincms/locale/tr/LC_MESSAGES/django.po | 979 ++++++++++++++++++++ feincms/locale/zh_CN/LC_MESSAGES/django.po | 648 ++++++++------ 18 files changed, 6630 insertions(+), 4822 deletions(-) create mode 100644 feincms/locale/en/LC_MESSAGES/django.mo create mode 100644 feincms/locale/pl/LC_MESSAGES/django.po create mode 100644 feincms/locale/tr/LC_MESSAGES/django.po diff --git a/feincms/locale/ca/LC_MESSAGES/django.po b/feincms/locale/ca/LC_MESSAGES/django.po index 8868b8d02..86ea7b459 100644 --- a/feincms/locale/ca/LC_MESSAGES/django.po +++ b/feincms/locale/ca/LC_MESSAGES/django.po @@ -1,103 +1,113 @@ -# Traducción española de FeinCMS -# Copyright (C) 2009 proycon -# This file is distributed under the same license as the FeinCMS package. -# Maarten van Gompel (proycon) <proycon@anaproy.nl>, 2009. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# Maarten van Gompel (proycon) <proycon@anaproy.nl>, 2009. msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2010-09-20 20:39+0100\n" -"Last-Translator: antoni aloy <aaloy@apsl.net>\n" -"Language-Team: ca <antoni.aloy@trespams.com>\n" -"Language: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Catalan\n" -"X-Poedit-SourceCharset: utf-8\n" -"X-Poedit-Country: SPAIN\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "plantilla" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "ordenació" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "idioma" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Tots" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Pare" -#: admin/filterspecs.py:95 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "títol" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s ha sigut mogut a una nova posició" -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "No entenc l'odre de moviment" -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "accions" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Segur que vols esborrar l'element?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "contingut de l'aplicació" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "continguts de l'aplicació" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "aplicació" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "actiu" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Es podran afegir nous comentaris" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "comentaris" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "públic" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "privat" @@ -125,58 +135,74 @@ msgstr "formulari de contacte" msgid "contact forms" msgstr "formularis de contacte" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "arxiu" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "arxius" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "imatge" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "llegenda" + +#: content/image/models.py:53 msgid "images" msgstr "imatges" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "posició" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(sense llegenda)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "arxiu de medis" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "arxius de medis" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "bloc" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "esquerra" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "dreta" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "tipus" @@ -188,20 +214,15 @@ msgstr "contingut en cruu" msgid "raw contents" msgstr "continguts en cruu" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "text" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "Ignora els avisos de validació de l'HTML" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " @@ -210,11 +231,15 @@ msgstr "" "La validació de l'HTML generà %(count)d avisos. Per favor, revisa el " "contingut actualitzat de la part inferior abans de continuar: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "text" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "text ric" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "texts rics" @@ -250,51 +275,51 @@ msgstr "feed RSS" msgid "RSS feeds" msgstr "feeds RSS" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "secció" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "seccions" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "plà" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "títol de la fila" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "títol de fila i columna" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "taula" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "taules" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "dades" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "plantilla de contingut" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "plantilles de continguts" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "enllaç de vídeo" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -302,36 +327,40 @@ msgstr "" "Això ha de ser un enllaç a un vídeo de Youtube o Vimeo. Per exemple: http://" "www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "vídeo" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "vídeos" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "publicat" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Això també es fa servir per la navegació generada automàticament." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "publicat el" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" "S'establirà automàticament quan marquis la casella superior de 'publicat'" -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "entrada" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "entrades" @@ -340,32 +369,52 @@ msgid "tags" msgstr "etiquetes" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "tradució de" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Deixa aquest camp buid per les entrades en l'idioma base" #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "traduccions disponibles" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "data de creació" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "data de modificació" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "tipus de contingut" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "data de publicació" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "publicar fins a" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Si la deixen en blanc l'entrada estarà activa per sempre" + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "visible de-fins a" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "Publicació segons la data" + #: module/extensions/featured.py:9 msgid "featured" msgstr "categoritzat" @@ -394,148 +443,225 @@ msgstr "Això serà afegit a la descripció per defecte" msgid "Search engine optimization" msgstr "Optimització per als motors de cerca" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Editar la traducció" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Crear traducció" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "traduccions" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Previsualitzar" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "tamany d'arxiu" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "creat" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "tipus d'arxiu" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "informació de l'arxiu" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "pare" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "categories" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "tipus d'arxiu" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "creat" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "drets de còpia" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "tamany d'arxiu" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "informació de l'arxiu" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Imatge" -#: module/medialibrary/models.py:281 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "document PDF" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Text" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Text ric" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binari" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "llegenda" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "descripció" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "traducció de l'arxiu de medis" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "traduccions dels arxius de medis" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Previsualitzar" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Aquesta URL ja està en ús en una plana activa." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Aquesta URL ja età en ús per una altra plana activa." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Altres opcions" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" -msgstr "" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "a la navegació" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Afegeix una plana filla." + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Veure a Lloc" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/models.py:256 +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "heretat" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "extensions" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "és activa" + +#: module/page/models.py:138 msgid "active" msgstr "actiu" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "a la navegació" - -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "URL sobrescrit" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -545,82 +671,26 @@ msgstr "" "tracti d'una URL local. Afecta tant a la navegació com a les URLs de les " "subplanes." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "redirecciona a" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "URL de destí per les redireccions automàtiques" -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "URL en caché" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "plana" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "planes" -#: module/page/models.py:297 module/page/models.py:782 -msgid "is active" -msgstr "és activa" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Aquesta URL ja està en ús en una plana activa." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Aquesta URL ja età en ús per una altra plana activa." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "Altres opcions" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Afegeix una plana filla." - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Veure a Lloc" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "heretat" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "extensions" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "data de publicació" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "publicar fins a" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Si la deixen en blanc l'entrada estarà activa per sempre" - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "visible de-fins a" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "Publicació segons la data" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "extracte" @@ -633,12 +703,12 @@ msgstr "Afegeix una breu descripció resumint el contingut de la plana" msgid "Excerpt" msgstr "Extracte" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "extensió de navegació" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -646,7 +716,7 @@ msgstr "" "Selecciona el mòdul que proveeix les subplanes si necessites personalitzar " "la navegació." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "Extensió de navegació" @@ -670,10 +740,6 @@ msgstr "Plana enllaçada" msgid "All content is inherited from this page if given." msgstr "Tot el contingut es heretat d'aquesta plana." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Plana enllaçada" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "títol del contingut" @@ -694,18 +760,6 @@ msgstr "Títol de la plana pel navegador. Per defecte el mateix que el títol." msgid "Titles" msgstr "Títols" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Editar la traducció" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Crear traducció" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "traduccions" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -745,10 +799,10 @@ msgid "Really change template? <br />All changes are saved." msgstr "Vols canviar la plantilla?<br /> Tots els canvis es guardaran." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Vols canviar la plantilla? <br/>Tots els canvis es guardaran i el contingut " "des de <strong>%(source_regions)s</strong> se mourà a <strong>" @@ -790,42 +844,51 @@ msgstr "" msgid "Add new item" msgstr "Afegir un nou element" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Guardar" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Acabar l'edició" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "editar" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "nou" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "amunt" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "avall" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "esborrar" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Inici" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -834,48 +897,47 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Dreceres" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Tancar l'arbre" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Expandir l'arbre" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Editar al Lloc" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "traducció de l'arxiu de medis" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -886,19 +948,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "categoria" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Puja un arxiu ZIP:" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Enviar" @@ -935,116 +1000,5 @@ msgstr "Enviar" msgid "Thanks!" msgstr "Gràcies!" -#~ msgid "rich text (ckeditor)" -#~ msgstr "text rico (ckeditor)" - -#~ msgid "rich texts (ckeditor)" -#~ msgstr "texts rics (ckeditor)" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Pots editar la plana copiada just aquí abaix." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Has reemplaçat %s. Pots continuar editant la ara plana activa aquí sota." - -#~ msgid "Move to" -#~ msgstr "Moure a" - -#~ msgid "Move" -#~ msgstr "Moure" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Reemplaçar la plana %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Crea una còpia oculta d'aquesta plana" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "%(name)s \"%(obj)s\" fue modificado con éxito." - -#~ msgid "You may edit it again below." -#~ msgstr "Puedes volver a editar el elemento." - -#~ msgid "You may add another %s below." -#~ msgstr "Puedes añadir un nuevo %s aquí debajo." - -#~ msgid "Insert as child" -#~ msgstr "Incluir como descendente" - -#~ msgid "Insert before" -#~ msgstr "Incluir antes" - -#~ msgid "is visible" -#~ msgstr "es visible" - -#~ msgid "Video from unknown portal" -#~ msgstr "Vídeo de un portal desconocido" - -#~ msgid "Tree saved successfully." -#~ msgstr "Árbol guardado con éxito." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "No se puede ser dependiente de si mismo." - -#~ msgid "Delete" -#~ msgstr "Borrar" - -#~ msgid "Save and add another" -#~ msgstr "Guardar y añadir otro" - -#~ msgid "Save and continue editing" -#~ msgstr "Guardar y continuar a editar" - -#~ msgid "Properties" -#~ msgstr "Propiedades" - -#~ msgid "Move selected item to" -#~ msgstr "Mover elemento seleccionado para" - -#~ msgid "OK" -#~ msgstr "Vale" - -#~ msgid "Add %(name)s" -#~ msgstr "Añadir %(name)s" - -#~ msgid "Edit" -#~ msgstr "editar" - -#~ msgid "Database error" -#~ msgstr "Error de base de dados" - -#~ msgid "view content" -#~ msgstr "mostrar contenido" - -#~ msgid "" -#~ "Could not parse the view content because the view is excluded from " -#~ "infanta handling." -#~ msgstr "" -#~ "No fue posible leer el contenido de la vista, porque esta está excluida " -#~ "del tratamiento de infanta." - -#~ msgid "Placeholder for the %(viewname)s calling %(viewfunc)s" -#~ msgstr "Substituto para %(viewname)s, que llama %(viewfunc)s" - -#~ msgid "Placeholder for calling %(viewfunc)s" -#~ msgstr "Substituto para llamar %(viewfunc)s" - -#~ msgid "not active" -#~ msgstr "inactivo" - -#~ msgid "Save tree" -#~ msgstr "Guardar árbol" - -#~ msgid "%(icon)s (not active)" -#~ msgstr "%(icon)s (inactivo)" - -#~ msgid "%(icon)s (until %(from)s)" -#~ msgstr "%(icon)s (hasta %(from)s)" - -#~ msgid "%(icon)s (since %(to)s)" -#~ msgstr "%(icon)s (a partir de %(to)s)" - -#~ msgid "%(icon)s (%(from)s – %(to)s)" -#~ msgstr "%(icon)s (%(from)s – %(to)s)" +#~ msgid "Symlinked page" +#~ msgstr "Plana enllaçada" diff --git a/feincms/locale/cs/LC_MESSAGES/django.po b/feincms/locale/cs/LC_MESSAGES/django.po index b52a26eda..ca5390629 100644 --- a/feincms/locale/cs/LC_MESSAGES/django.po +++ b/feincms/locale/cs/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-05-08 19:16+0200\n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,86 +17,96 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" -#: models.py:419 content/template/models.py:59 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "šablona" -#: models.py:550 +#: models.py:551 msgid "ordering" msgstr "řazení" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:102 +#: module/extensions/translations.py:119 msgid "language" msgstr "jazyk" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "vše" -#: admin/filterspecs.py:57 module/page/models.py:222 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "rodič" -#: admin/filterspecs.py:95 -#: templates/admin/medialibrary/mediafile/change_list.html:15 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "kategorie" -#: admin/item_editor.py:163 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "změň %s" -#: admin/tree_editor.py:215 content/rss/models.py:20 -#: content/section/models.py:31 module/blog/models.py:30 -#: module/medialibrary/models.py:55 module/page/models.py:220 -#: module/page/models.py:299 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "Název" -#: admin/tree_editor.py:385 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s přesunut na novou pozici" -#: admin/tree_editor.py:389 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "Nesrozumitelné přesunutí" -#: admin/tree_editor.py:398 +#: admin/tree_editor.py:417 msgid "actions" msgstr "akce" -#: content/application/models.py:263 +#: admin/tree_editor.py:429 +#, python-format +msgid "Successfully deleted %s items." +msgstr "" + +#: admin/tree_editor.py:437 +#, fuzzy, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Obnov smazané %(verbose_name)s" + +#: content/application/models.py:272 msgid "application content" msgstr "aplikační obsah" -#: content/application/models.py:264 +#: content/application/models.py:273 msgid "application contents" msgstr "aplikační obsahy" -#: content/application/models.py:295 +#: content/application/models.py:298 msgid "application" msgstr "aplikace" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "zapnutý" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Komentáře povoleny" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "komentáře" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "veřejný" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "neveřejný" @@ -124,58 +134,76 @@ msgstr "kontaktní formulář" msgid "contact forms" msgstr "kontaktní formuláře" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:105 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "soubor" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "soubory" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "obrázek" -#: content/image/models.py:29 +#: content/image/models.py:46 +#, fuzzy +msgid "alternate text" +msgstr "šablonový obsah" + +#: content/image/models.py:47 +#, fuzzy +msgid "Description of image" +msgstr "popis" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "název" + +#: content/image/models.py:53 msgid "images" msgstr "obrázky" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "pozice" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(bez názvu)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:47 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:118 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "mediální soubor" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:119 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "mediální soubory" -#: content/medialibrary/models.py:130 +#: content/medialibrary/models.py:139 msgid "block" msgstr "do bloku" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:140 msgid "left" msgstr "vlevo" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:141 msgid "right" msgstr "vpravo" -#: content/medialibrary/v2.py:49 content/section/models.py:52 -#: content/section/models.py:60 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "typ" @@ -187,32 +215,32 @@ msgstr "binární obsah" msgid "raw contents" msgstr "binární obsahy" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:32 -msgid "text" -msgstr "text" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "čisté HTML " -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "ignorovat HTML validační varovnání" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "HTML validace vyplivla %(count)d varování. Prosím zkontroluj " -"obsah níže před pokračováním: %(messages)s" +msgstr "" +"HTML validace vyplivla %(count)d varování. Prosím zkontroluj obsah níže před " +"pokračováním: %(messages)s" + +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "text" -#: content/richtext/models.py:89 +#: content/richtext/models.py:85 msgid "rich text" msgstr "" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "" @@ -220,7 +248,9 @@ msgstr "" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "RSS pole je měněno několikrát za den. Změna v titulku bude patrná při přístí změně RSS kanálu." +msgstr "" +"RSS pole je měněno několikrát za den. Změna v titulku bude patrná při přístí " +"změně RSS kanálu." #: content/rss/models.py:22 msgid "link" @@ -246,35 +276,35 @@ msgstr "RSS kanál" msgid "RSS feeds" msgstr "RSS kanály" -#: content/section/models.py:36 +#: content/section/models.py:41 msgid "section" msgstr "sekce" -#: content/section/models.py:37 +#: content/section/models.py:42 msgid "sections" msgstr "sekce" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "prostý" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "titulní řádka" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "titulní řádka a sloupec" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tabulka" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tabulky" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "" @@ -294,8 +324,9 @@ msgstr "odkaz na video" msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" -msgstr "Toto má být odkaz na youtube nebo vimeo video, např. http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Toto má být odkaz na youtube nebo vimeo video, např. http://www.youtube.com/" +"watch?v=zmj1rpzDRZ0" #: content/video/models.py:30 msgid "video" @@ -305,31 +336,32 @@ msgstr "video" msgid "videos" msgstr "videoa" -#: contrib/tagging.py:113 +#: contrib/tagging.py:117 msgid "Tagging" msgstr "Tagy" -#: module/blog/models.py:29 +#: module/blog/models.py:28 msgid "published" msgstr "publikovaný" -#: module/blog/models.py:31 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Toto je také použito pro generovanou navigaci" -#: module/blog/models.py:34 +#: module/blog/models.py:33 msgid "published on" msgstr "publikovaný" -#: module/blog/models.py:35 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "Bude automaticky nastaven jakmile klikneš na zaškrtávátko `publikovaný` výše." +msgstr "" +"Bude automaticky nastaven jakmile klikneš na zaškrtávátko `publikovaný` výše." -#: module/blog/models.py:40 +#: module/blog/models.py:39 msgid "entry" msgstr "Článek" -#: module/blog/models.py:41 +#: module/blog/models.py:40 msgid "entries" msgstr "Články" @@ -338,25 +370,25 @@ msgid "tags" msgstr "tagy" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "překlad" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Nech prázdné pro články v primárním jazyce" #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:40 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "překlady k dispozici" -#: module/extensions/changedate.py:36 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "datum vytvoření" -#: module/extensions/changedate.py:37 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "datum úpravy" @@ -364,23 +396,23 @@ msgstr "datum úpravy" msgid "content types" msgstr "typy obsahu" -#: module/extensions/datepublisher.py:48 +#: module/extensions/datepublisher.py:49 msgid "publication date" msgstr "datum publikace" -#: module/extensions/datepublisher.py:50 +#: module/extensions/datepublisher.py:51 msgid "publication end date" msgstr "konec publikace" -#: module/extensions/datepublisher.py:52 +#: module/extensions/datepublisher.py:53 msgid "Leave empty if the entry should stay active forever." msgstr "Nech prázdné pro články, které mají být publikovány stále" -#: module/extensions/datepublisher.py:79 +#: module/extensions/datepublisher.py:80 msgid "visible from - to" msgstr "Publikováno od - do" -#: module/extensions/datepublisher.py:89 +#: module/extensions/datepublisher.py:90 msgid "Date-based publishing" msgstr "Publikování na základě data" @@ -412,252 +444,255 @@ msgstr "Toto bude přidáno k výchozímu popisu" msgid "Search engine optimization" msgstr "Optimalizace pro vyhledávače" -#: module/extensions/translations.py:175 +#: module/extensions/translations.py:192 msgid "Edit translation" msgstr "" -#: module/extensions/translations.py:178 +#: module/extensions/translations.py:195 msgid "Create translation" msgstr "Vytvoř překlad" -#: module/extensions/translations.py:183 +#: module/extensions/translations.py:200 msgid "translations" msgstr "překlady" -#: module/medialibrary/models.py:58 +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" +"Nemůže být přepsán jiným typem (pokoušíš se přepsat %(old_ext)s s " +"%(new_ext)s)" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." +msgstr[1] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "Přiděj vybrané mediální soubory do kategorie" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "ZIP archiv exporotován jako %s" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "export ZIP archivu selhal: %s" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "Vyexportuj vybrané mediální soubory jako zip archiv" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "náhled" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "velikost souboru" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "vytvoreno" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "typ souboru" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "info o souboru" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "%d souborů importováno" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "import ZIPu selhal: %s" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "Žádný vstupní soubor" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "rodič" -#: module/medialibrary/models.py:60 module/page/models.py:221 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "" -#: module/medialibrary/models.py:64 +#: module/medialibrary/models.py:49 msgid "category" msgstr "kategorie" -#: module/medialibrary/models.py:65 module/medialibrary/models.py:111 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "kategorie" -#: module/medialibrary/models.py:106 module/medialibrary/models.py:195 -msgid "file type" -msgstr "typ souboru" - -#: module/medialibrary/models.py:107 module/medialibrary/models.py:133 -msgid "created" -msgstr "vytvoreno" - -#: module/medialibrary/models.py:108 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "" -#: module/medialibrary/models.py:109 module/medialibrary/models.py:128 -msgid "file size" -msgstr "velikost souboru" - -#: module/medialibrary/models.py:216 -msgid "file info" -msgstr "info o souboru" - -#: module/medialibrary/models.py:293 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "obrázek" -#: module/medialibrary/models.py:294 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "" -#: module/medialibrary/models.py:295 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:296 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "PDF dokument" -#: module/medialibrary/models.py:297 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "" -#: module/medialibrary/models.py:298 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "" -#: module/medialibrary/models.py:299 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "" -#: module/medialibrary/models.py:300 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:301 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:302 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:303 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:304 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binární" -#: module/medialibrary/models.py:320 -msgid "caption" -msgstr "název" - -#: module/medialibrary/models.py:321 +#: module/medialibrary/models.py:236 msgid "description" msgstr "popis" -#: module/medialibrary/models.py:324 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "překlad mediálního souboru" -#: module/medialibrary/models.py:325 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "překlady mediálního souboru" -#: module/medialibrary/models.py:347 -#: templates/admin/feincms/page/page/item_editor.html:14 -msgid "Preview" -msgstr "náhled" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Toto URL je už obsazeno aktivní stránkou." -#: module/medialibrary/models.py:367 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." -msgstr[1] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Toto URL je už obsazeno jinou stránkou." -#: module/medialibrary/models.py:385 -msgid "Add selected media files to category" -msgstr "Přiděj vybrané mediální soubory do kategorie" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Další nastavení" -#: module/medialibrary/models.py:394 -#, python-format -msgid "ZIP file exported as %s" -msgstr "ZIP archiv exporotován jako %s" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "v navigaci" -#: module/medialibrary/models.py:396 -#, python-format -msgid "ZIP file export failed: %s" -msgstr "export ZIP archivu selhal: %s" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Přidej podřízenou stránku" -#: module/medialibrary/models.py:400 -msgid "Export selected media files as zip file" -msgstr "Vyexportuj vybrané mediální soubory jako zip archiv" +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Zobrazena na sajtě." -#: module/medialibrary/models.py:423 -#, python-format +#: module/page/modeladmins.py:130 msgid "" -"Cannot overwrite with different file type (attempt to overwrite a " -"%(old_ext)s with a %(new_ext)s)" -msgstr "Nemůže být přepsán jiným typem (pokoušíš se přepsat " -"%(old_ext)s s %(new_ext)s)" +"The content from the original translation has been copied to the newly " +"created page." +msgstr "Originálnío překlad zkopírován do nově vytvořené stránky." -#: module/medialibrary/models.py:466 -#, python-format -msgid "%d files imported" -msgstr "%d souborů importováno" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" +msgstr "Nemáte dostatečná oprávnění pro editaci tohoto objektu" -#: module/medialibrary/models.py:468 -#, python-format -msgid "ZIP import failed: %s" -msgstr "import ZIPu selhal: %s" +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "zděděný" -#: module/medialibrary/models.py:470 -msgid "No input file given" -msgstr "Žádný vstupní soubor" +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "rozšíření" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "je aktivní" -#: module/page/models.py:217 +#: module/page/models.py:138 msgid "active" msgstr "aktivní" -#: module/page/models.py:224 module/page/models.py:731 -msgid "in navigation" -msgstr "v navigaci" - -#: module/page/models.py:225 +#: module/page/models.py:146 msgid "override URL" msgstr "vynucené URL" -#: module/page/models.py:226 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." -msgstr "Přepíše cílové URL. Ujisti se, že máš \"/\" na začátku a na konci pro lokální URL." -"Toto ovlivňuje navigaci cílové stránky i podstránek" +msgstr "" +"Přepíše cílové URL. Ujisti se, že máš \"/\" na začátku a na konci pro " +"lokální URL.Toto ovlivňuje navigaci cílové stránky i podstránek" -#: module/page/models.py:227 +#: module/page/models.py:148 msgid "redirect to" msgstr "přesměruj na" -#: module/page/models.py:228 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "Cílová adresa pro automatické přeměrování" -#: module/page/models.py:229 +#: module/page/models.py:150 msgid "Cached URL" msgstr "" -#: module/page/models.py:240 +#: module/page/models.py:161 msgid "page" msgstr "stránka" -#: module/page/models.py:241 +#: module/page/models.py:162 msgid "pages" msgstr "stránky" -#: module/page/models.py:258 module/page/models.py:811 -msgid "is active" -msgstr "je aktivní" - -#: module/page/models.py:641 -msgid "This URL is already taken by an active page." -msgstr "Toto URL je už obsazeno aktivní stránkou." - -#: module/page/models.py:659 -msgid "This URL is already taken by another active page." -msgstr "Toto URL je už obsazeno jinou stránkou." - -#: module/page/models.py:683 -msgid "Other options" -msgstr "Další nastavení" - -#: module/page/models.py:742 -msgid "Add child page" -msgstr "Přidej podřízenou stránku" - -#: module/page/models.py:744 templates/admin/feincms/content_inline.html:9 -msgid "View on site" -msgstr "Zobrazena na sajtě." - -#: module/page/models.py:774 -msgid "" -"The content from the original translation has been copied to the newly " -"created page." -msgstr "Originálnío překlad zkopírován do nově vytvořené stránky." - -#: module/page/models.py:788 -msgid "You don't have the necessary permissions to edit this object" -msgstr "Nemáte dostatečná oprávnění pro editaci tohoto objektu" - -#: module/page/models.py:803 -msgid "inherited" -msgstr "zděděný" - -#: module/page/models.py:807 -msgid "extensions" -msgstr "rozšíření" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "" @@ -670,18 +705,20 @@ msgstr "" msgid "Excerpt" msgstr "výňatek" -#: module/page/extensions/navigation.py:74 -#: module/page/extensions/navigation.py:94 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "rozšíření navigace" -#: module/page/extensions/navigation.py:96 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "Vyber modul nabízející podstránky pro tuto stránku jestli chceš upravit navigaci." +msgstr "" +"Vyber modul nabízející podstránky pro tuto stránku jestli chceš upravit " +"navigaci." -#: module/page/extensions/navigation.py:109 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "rozšíření navigace" @@ -705,10 +742,6 @@ msgstr "propojená stránka" msgid "All content is inherited from this page if given." msgstr "Všechen obsah je poděděn do této stránky, pakliže vybrána" -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Propojená stránka" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "Název obsahu" @@ -767,12 +800,14 @@ msgid "Really change template? <br />All changes are saved." msgstr "Opravdu změnit šablonu? <br />Všechny změny uloženy." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." -msgstr "Opravdu změnit šablonu? <br />Všechny změny uloženy a obsah <strong>" -"%(source_regions)s</strong> je přesunut do <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +msgstr "" +"Opravdu změnit šablonu? <br />Všechny změny uloženy a obsah <strong>" +"%(source_regions)s</strong> je přesunut do <strong>%(target_region)s</" +"strong>." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -802,7 +837,9 @@ msgstr "Region je prázdný" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Obsah z nadřazené stránky je automaticky zděděn. Přidej nějaký obsah, který ho přepíše." +msgstr "" +"Obsah z nadřazené stránky je automaticky zděděn. Přidej nějaký obsah, který " +"ho přepíše." #: templates/admin/feincms/content_editor.html:23 msgid "Add new item" @@ -821,38 +858,38 @@ msgstr "Smaž" msgid "Save" msgstr "Ulož" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Ukončit editaci" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "edituj" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "nový" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "nahoru" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "dolů" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "odeber" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:22 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Domů" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "Obnov smazané %(verbose_name)s" @@ -861,16 +898,16 @@ msgstr "Obnov smazané %(verbose_name)s" msgid "Press the save button below to recover this version of the object." msgstr "Zmáčkni tlačítko ulož níže pro obnovení této verze objektu." -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "Historie" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "Revertuj %(verbose_name)s" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "Zmáčkni tlačítko ulož níže pro revertování na tuto verzi objektu." @@ -890,11 +927,11 @@ msgstr "Zabal strom" msgid "Filter" msgstr "Filtruj" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Edituj přímo na webu" -#: templates/admin/feincms/page/page/item_editor.html:26 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "Přidej" @@ -919,15 +956,15 @@ msgstr "Přidej do kategorie" msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Nahrát dávku v ZIP souboru:" -#: templates/admin/medialibrary/mediafile/change_list.html:22 +#: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" msgstr "Přepsat" -#: templates/admin/medialibrary/mediafile/change_list.html:25 +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Poslat" @@ -937,8 +974,12 @@ msgid "%(comment_count)s comments." msgstr "%(comment_count)s komentářů" #: templates/content/comments/default.html:18 -#, python-format -msgid "%(comment_username)s said on %(comment_submit_date)s<br />" +#, fuzzy, python-format +msgid "" +"\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " msgstr "%(comment_username)s řekl v %(comment_submit_date)s <br />" #: templates/content/comments/default.html:28 @@ -956,3 +997,6 @@ msgstr "Odeslat" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Díky!" + +#~ msgid "Symlinked page" +#~ msgstr "Propojená stránka" diff --git a/feincms/locale/de/LC_MESSAGES/django.po b/feincms/locale/de/LC_MESSAGES/django.po index 237b3e6c9..450967107 100644 --- a/feincms/locale/de/LC_MESSAGES/django.po +++ b/feincms/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-03-09 16:42+0100\n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,86 +17,96 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: models.py:419 content/template/models.py:59 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "Template" -#: models.py:550 +#: models.py:551 msgid "ordering" msgstr "Sortierung" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:102 +#: module/extensions/translations.py:119 msgid "language" msgstr "Sprache" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Alle" -#: admin/filterspecs.py:57 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Übergeordnet" -#: admin/filterspecs.py:95 -#: templates/admin/medialibrary/mediafile/change_list.html:15 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategorie" -#: admin/item_editor.py:163 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "%s ändern" -#: admin/tree_editor.py:214 content/rss/models.py:20 -#: content/section/models.py:31 module/blog/models.py:30 -#: module/medialibrary/models.py:43 module/page/models.py:141 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 #: module/page/models.py:199 msgid "title" msgstr "Titel" -#: admin/tree_editor.py:389 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s wurde an eine neue Position verschoben." -#: admin/tree_editor.py:393 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "Unbekannter Verschiebe-Befehl." -#: admin/tree_editor.py:402 +#: admin/tree_editor.py:417 msgid "actions" msgstr "Aktionen" -#: content/application/models.py:264 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Element wirklich löschen?" + +#: admin/tree_editor.py:437 +#, fuzzy, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Gelöschtes Element %(verbose_name)s wiederherstellen" + +#: content/application/models.py:272 msgid "application content" msgstr "Applikation" -#: content/application/models.py:265 +#: content/application/models.py:273 msgid "application contents" msgstr "Applikationen" -#: content/application/models.py:296 +#: content/application/models.py:298 msgid "application" msgstr "Applikation" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "aktiviert" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Neue Kommentare können hinzugefügt werden" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "Kommentare" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "veröffentlicht" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "nicht öffentlich" @@ -125,7 +135,7 @@ msgid "contact forms" msgstr "Kontaktformulare" #: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:86 +#: module/medialibrary/models.py:84 msgid "file" msgstr "Datei" @@ -145,7 +155,7 @@ msgstr "Textalternative" msgid "Description of image" msgstr "Beschreibung des Bildes" -#: content/image/models.py:48 module/medialibrary/models.py:237 +#: content/image/models.py:48 module/medialibrary/models.py:235 msgid "caption" msgstr "Legende" @@ -153,8 +163,8 @@ msgstr "Legende" msgid "images" msgstr "Bilder" -#: content/image/models.py:79 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "Position" @@ -162,36 +172,36 @@ msgstr "Position" msgid "format" msgstr "Format" -#: content/medialibrary/models.py:38 +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(Keine Legende)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:47 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:99 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "Mediendatei" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:100 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "Mediendateien" -#: content/medialibrary/models.py:130 +#: content/medialibrary/models.py:139 msgid "block" msgstr "Block" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:140 msgid "left" msgstr "Links" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:141 msgid "right" msgstr "Rechts" -#: content/medialibrary/v2.py:49 content/section/models.py:52 -#: content/section/models.py:60 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "Typ" @@ -203,20 +213,15 @@ msgstr "Roh-Inhalt" msgid "raw contents" msgstr "Roh-Inhalte" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:32 -msgid "text" -msgstr "Text" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "HTML-Validierungswarnungen ignorieren" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " @@ -225,11 +230,15 @@ msgstr "" "Die HTML-Validierung ergab %(count)d Warnungen. Bitte überprüfen Sie den " "aktualisierten Inhalt bevor Sie fortfahren: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "Text" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "Text" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "Texte" @@ -265,35 +274,35 @@ msgstr "RSS Feed" msgid "RSS feeds" msgstr "RSS Feeds" -#: content/section/models.py:36 +#: content/section/models.py:41 msgid "section" msgstr "Sektion" -#: content/section/models.py:37 +#: content/section/models.py:42 msgid "sections" msgstr "Sektionen" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "schlicht" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "Titelzeile" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "Titelzeile und -spalte" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "Tabelle" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "Tabellen" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "Daten" @@ -325,31 +334,31 @@ msgstr "Video" msgid "videos" msgstr "Videos" -#: contrib/tagging.py:113 +#: contrib/tagging.py:117 msgid "Tagging" msgstr "" -#: module/blog/models.py:29 +#: module/blog/models.py:28 msgid "published" msgstr "veröffentlicht" -#: module/blog/models.py:31 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Dies wird auch für die generierte Navigation verwendet." -#: module/blog/models.py:34 +#: module/blog/models.py:33 msgid "published on" msgstr "veröffentlicht am" -#: module/blog/models.py:35 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Wird automatisch gesetzt, wenn `veröffentlicht` aktiviert ist." -#: module/blog/models.py:40 +#: module/blog/models.py:39 msgid "entry" msgstr "Eintrag" -#: module/blog/models.py:41 +#: module/blog/models.py:40 msgid "entries" msgstr "Einträge" @@ -358,12 +367,12 @@ msgid "tags" msgstr "Begriffe" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "Übersetzung von" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Dieses Feld für Einträge in der Primärsprache leer lassen." @@ -372,11 +381,11 @@ msgstr "Dieses Feld für Einträge in der Primärsprache leer lassen." msgid "available translations" msgstr "Verfügbare Übersetzungen" -#: module/extensions/changedate.py:36 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "Erstellt um" -#: module/extensions/changedate.py:37 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "Verändert um" @@ -384,23 +393,23 @@ msgstr "Verändert um" msgid "content types" msgstr "Inhaltstypen" -#: module/extensions/datepublisher.py:48 +#: module/extensions/datepublisher.py:49 msgid "publication date" msgstr "Veröffentlichen am" -#: module/extensions/datepublisher.py:50 +#: module/extensions/datepublisher.py:51 msgid "publication end date" msgstr "Veröffentlicht bis" -#: module/extensions/datepublisher.py:52 +#: module/extensions/datepublisher.py:53 msgid "Leave empty if the entry should stay active forever." msgstr "Leer lassen wenn das Element ewig aktiv bleiben soll." -#: module/extensions/datepublisher.py:79 +#: module/extensions/datepublisher.py:80 msgid "visible from - to" msgstr "sichtbar von – bis" -#: module/extensions/datepublisher.py:89 +#: module/extensions/datepublisher.py:90 msgid "Date-based publishing" msgstr "Datumsbasierte Veröffentlichung" @@ -432,23 +441,23 @@ msgstr "Diese Beschreibung wird vor der Standard-Beschreibung eingefügt." msgid "Search engine optimization" msgstr "Suchmaschinenoptimierung" -#: module/extensions/translations.py:175 +#: module/extensions/translations.py:192 msgid "Edit translation" msgstr "Übersetzungen bearbeiten" -#: module/extensions/translations.py:178 +#: module/extensions/translations.py:195 msgid "Create translation" msgstr "Übersetzung erstellen" -#: module/extensions/translations.py:183 +#: module/extensions/translations.py:200 msgid "translations" msgstr "Übersetzungen" -#: module/medialibrary/forms.py:25 +#: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" msgstr "Dies würde eine Schleife in der Hierarchie erzeugen" -#: module/medialibrary/forms.py:57 +#: module/medialibrary/forms.py:64 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " @@ -457,190 +466,190 @@ msgstr "" "Kann nur gleiche Dateitypen ersetzen (versuchte ein %(old_ext)s mit einem " "%(new_ext)s zu überschreiben)" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:57 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "%(count)d Mediendatei zu %(category)s hinzugefügt." msgstr[1] "%(count)d Mediendateien zu %(category)s hinzugefügt." -#: module/medialibrary/modeladmins.py:76 +#: module/medialibrary/modeladmins.py:75 msgid "Add selected media files to category" msgstr "Ausgewählte zu Kategorie hinzufügen" -#: module/medialibrary/modeladmins.py:85 +#: module/medialibrary/modeladmins.py:84 #, python-format msgid "ZIP file exported as %s" msgstr "ZIP-Datei exportiert als %s" -#: module/medialibrary/modeladmins.py:87 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file export failed: %s" msgstr "ZIP-Datei Export fehlgeschlagen: %s" -#: module/medialibrary/modeladmins.py:92 +#: module/medialibrary/modeladmins.py:91 msgid "Export selected media files as zip file" msgstr "Ausgewählte Mediendateien als ZIP exportieren" -#: module/medialibrary/modeladmins.py:141 -#: templates/admin/feincms/page/page/item_editor.html:14 +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Vorschau" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:90 +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 msgid "file size" msgstr "Dateigrösse" -#: module/medialibrary/modeladmins.py:151 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 msgid "created" msgstr "Erstellt" -#: module/medialibrary/modeladmins.py:170 module/medialibrary/models.py:87 +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 msgid "file type" msgstr "Dateityp" -#: module/medialibrary/modeladmins.py:191 +#: module/medialibrary/modeladmins.py:184 msgid "file info" msgstr "Dateiinfo" -#: module/medialibrary/modeladmins.py:203 +#: module/medialibrary/modeladmins.py:196 #, python-format msgid "%d files imported" msgstr "%d Dateien importiert" -#: module/medialibrary/modeladmins.py:205 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "ZIP import failed: %s" msgstr "ZIP-Import schlug fehl: %s" -#: module/medialibrary/modeladmins.py:207 +#: module/medialibrary/modeladmins.py:200 msgid "No input file given" msgstr "Keine Datei angegeben" -#: module/medialibrary/models.py:46 +#: module/medialibrary/models.py:43 msgid "parent" msgstr "Übergeordnet" -#: module/medialibrary/models.py:48 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "Slug" -#: module/medialibrary/models.py:52 +#: module/medialibrary/models.py:49 msgid "category" msgstr "Kategorie" -#: module/medialibrary/models.py:53 module/medialibrary/models.py:92 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "Kategorien" -#: module/medialibrary/models.py:89 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "Copyright" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Bild" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "PDF-Dokument" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:214 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Text" -#: module/medialibrary/models.py:215 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Text" -#: module/medialibrary/models.py:216 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "ZIP-Archiv" -#: module/medialibrary/models.py:217 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:218 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:219 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:220 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binärdaten" -#: module/medialibrary/models.py:238 +#: module/medialibrary/models.py:236 msgid "description" msgstr "Beschreibung" -#: module/medialibrary/models.py:241 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "Mediendatei-Übersetzung" -#: module/medialibrary/models.py:242 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "Mediendatei-Übersetzungen" -#: module/page/forms.py:113 +#: module/page/forms.py:118 msgid "This URL is already taken by an active page." msgstr "Die URL wird schon von einer aktiven Seite verwendet." -#: module/page/forms.py:131 +#: module/page/forms.py:136 msgid "This URL is already taken by another active page." msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." -#: module/page/modeladmins.py:40 +#: module/page/modeladmins.py:41 msgid "Other options" msgstr "Weitere Optionen" -#: module/page/modeladmins.py:88 module/page/models.py:145 +#: module/page/modeladmins.py:89 module/page/models.py:145 msgid "in navigation" msgstr "Im Menü" -#: module/page/modeladmins.py:99 +#: module/page/modeladmins.py:100 msgid "Add child page" msgstr "Unterseite hinzufügen" -#: module/page/modeladmins.py:101 +#: module/page/modeladmins.py:102 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Auf der Webseite anzeigen" -#: module/page/modeladmins.py:129 +#: module/page/modeladmins.py:130 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:143 +#: module/page/modeladmins.py:144 msgid "You don't have the necessary permissions to edit this object" msgstr "Ungenügende Berechtigung um dieses Objekt zu bearbeiten" -#: module/page/modeladmins.py:158 +#: module/page/modeladmins.py:159 msgid "inherited" msgstr "geerbt" -#: module/page/modeladmins.py:162 +#: module/page/modeladmins.py:163 msgid "extensions" msgstr "Erweiterungen" -#: module/page/modeladmins.py:166 module/page/models.py:179 +#: module/page/modeladmins.py:167 module/page/models.py:179 msgid "is active" msgstr "Aktiv" @@ -694,18 +703,18 @@ msgstr "Kurze Zusammenfassung des Seiteninhaltes." msgid "Excerpt" msgstr "Auszug" -#: module/page/extensions/navigation.py:74 -#: module/page/extensions/navigation.py:94 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "Navigations-Erweiterung" -#: module/page/extensions/navigation.py:96 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "Wähle das Modul aus, welches weitere Navigationspunkte erstellt." -#: module/page/extensions/navigation.py:109 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "Navigations-Erweiterung" @@ -730,10 +739,6 @@ msgid "All content is inherited from this page if given." msgstr "" "Der angezeigte Inhalt wird durch den Inhalt der angegebenen Seite ersetzt." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Verbundene Seite" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "Inhaltstitel" @@ -793,10 +798,10 @@ msgid "Really change template? <br />All changes are saved." msgstr "Template wirklich ändern? <br />Alle Änderungen werden gespeichert." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Template wirklich ändern? <br />Alle Änderungen werden gespeichert und " "Inhalt aus <strong>%(source_regions)s</strong> nach <strong>" @@ -851,58 +856,61 @@ msgstr "Entfernen" msgid "Save" msgstr "Sichern" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Fertig bearbeitet" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "bearbeiten" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "neu" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "rauf" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "runter" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "entfernen" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:22 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Startseite" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "Gelöschtes Element %(verbose_name)s wiederherstellen" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "Diese Version kann durch Drücken des Speichern-Knopfes wiederhergestellt werden" +msgstr "" +"Diese Version kann durch Drücken des Speichern-Knopfes wiederhergestellt " +"werden" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "Verlauf" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "Alte Version von %(verbose_name)s wiederherstellen" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "Diese Version kann durch Drücken des Speichern-Knopfes zurückgeholt werden" +msgstr "" +"Diese Version kann durch Drücken des Speichern-Knopfes zurückgeholt werden" #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -920,11 +928,11 @@ msgstr "Alles aufklappen" msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "In der Seite bearbeiten" -#: templates/admin/feincms/page/page/item_editor.html:26 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "Hinzufügen" @@ -950,15 +958,15 @@ msgstr "Zu Kategorie hinzufügen" msgid "Cancel" msgstr "Abbrechen" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Massenupload mit ZIP Dateien:" -#: templates/admin/medialibrary/mediafile/change_list.html:22 +#: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" msgstr "Überschreiben" -#: templates/admin/medialibrary/mediafile/change_list.html:25 +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Senden" @@ -994,6 +1002,9 @@ msgstr "Senden" msgid "Thanks!" msgstr "Danke!" +#~ msgid "Symlinked page" +#~ msgstr "Verbundene Seite" + #~ msgid "rich text (ckeditor)" #~ msgstr "Text (ckeditor)" diff --git a/feincms/locale/en/LC_MESSAGES/django.mo b/feincms/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..13b2d960fd625ebd7572da3f38343abb23125275 GIT binary patch literal 378 zcmYL^K~KUk7=|%=+R?Lz9=zd)8yba*hRO;qt{WMHL~j-9tihIah3F6Q@A+H&mKb@H zCq4A}+V}f8KKgE94v-V%6gfoBkS0B3h?jjl8|Ob$XW!M*L$ZQ}a<#UGk|`TKvI!>( zUd)m_3ktQd&V#5cy@LB~RYPeh38r}oBd4UtA&8|{lyt+W3*iNXeG*;K%j<R+g&~Si zsGV*e|MQ+WD?sEBGxCsAk+h%lj0dT#J(NzGdM&+ml#J(TN-`!m8F0apbjaek;Ir8s zs;1h?N<pdQ2PG-XCiAB9AWesB-LbCPJ6KgDg75c>I$<!f#w&y0eQmI}SD*fTvzFT2 hkmZ|nweq*~atyt_*VKAd4!Bv`l{OV6y%+6+)-PD9W=8-3 literal 0 HcmV?d00001 diff --git a/feincms/locale/en/LC_MESSAGES/django.po b/feincms/locale/en/LC_MESSAGES/django.po index bc17380f6..f39fd0b78 100644 --- a/feincms/locale/en/LC_MESSAGES/django.po +++ b/feincms/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-03-09 16:47+0100\n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,86 +17,96 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: models.py:419 content/template/models.py:59 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "" -#: models.py:550 +#: models.py:551 msgid "ordering" msgstr "" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:102 +#: module/extensions/translations.py:119 msgid "language" msgstr "" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "" -#: admin/filterspecs.py:57 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "" -#: admin/filterspecs.py:95 -#: templates/admin/medialibrary/mediafile/change_list.html:15 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "" -#: admin/item_editor.py:163 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "" -#: admin/tree_editor.py:214 content/rss/models.py:20 -#: content/section/models.py:31 module/blog/models.py:30 -#: module/medialibrary/models.py:43 module/page/models.py:141 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 #: module/page/models.py:199 msgid "title" msgstr "" -#: admin/tree_editor.py:389 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:393 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:402 +#: admin/tree_editor.py:417 msgid "actions" msgstr "" -#: content/application/models.py:264 +#: admin/tree_editor.py:429 +#, python-format +msgid "Successfully deleted %s items." +msgstr "" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "" -#: content/application/models.py:265 +#: content/application/models.py:273 msgid "application contents" msgstr "" -#: content/application/models.py:296 +#: content/application/models.py:298 msgid "application" msgstr "" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "" @@ -125,7 +135,7 @@ msgid "contact forms" msgstr "" #: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:86 +#: module/medialibrary/models.py:84 msgid "file" msgstr "" @@ -145,7 +155,7 @@ msgstr "" msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:237 +#: content/image/models.py:48 module/medialibrary/models.py:235 msgid "caption" msgstr "" @@ -153,8 +163,8 @@ msgstr "" msgid "images" msgstr "" -#: content/image/models.py:79 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "" @@ -162,36 +172,36 @@ msgstr "" msgid "format" msgstr "" -#: content/medialibrary/models.py:38 +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:47 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:99 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:100 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "" -#: content/medialibrary/models.py:130 +#: content/medialibrary/models.py:139 msgid "block" msgstr "" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:140 msgid "left" msgstr "" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:141 msgid "right" msgstr "" -#: content/medialibrary/v2.py:49 content/section/models.py:52 -#: content/section/models.py:60 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "" @@ -203,31 +213,30 @@ msgstr "" msgid "raw contents" msgstr "" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:32 -msgid "text" -msgstr "" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "" @@ -261,35 +270,35 @@ msgstr "" msgid "RSS feeds" msgstr "" -#: content/section/models.py:36 +#: content/section/models.py:41 msgid "section" msgstr "" -#: content/section/models.py:37 +#: content/section/models.py:42 msgid "sections" msgstr "" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "" @@ -319,31 +328,31 @@ msgstr "" msgid "videos" msgstr "" -#: contrib/tagging.py:113 +#: contrib/tagging.py:117 msgid "Tagging" msgstr "" -#: module/blog/models.py:29 +#: module/blog/models.py:28 msgid "published" msgstr "" -#: module/blog/models.py:31 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "" -#: module/blog/models.py:34 +#: module/blog/models.py:33 msgid "published on" msgstr "" -#: module/blog/models.py:35 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" -#: module/blog/models.py:40 +#: module/blog/models.py:39 msgid "entry" msgstr "" -#: module/blog/models.py:41 +#: module/blog/models.py:40 msgid "entries" msgstr "" @@ -352,12 +361,12 @@ msgid "tags" msgstr "" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "" @@ -366,11 +375,11 @@ msgstr "" msgid "available translations" msgstr "" -#: module/extensions/changedate.py:36 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "" -#: module/extensions/changedate.py:37 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "" @@ -378,23 +387,23 @@ msgstr "" msgid "content types" msgstr "" -#: module/extensions/datepublisher.py:48 +#: module/extensions/datepublisher.py:49 msgid "publication date" msgstr "" -#: module/extensions/datepublisher.py:50 +#: module/extensions/datepublisher.py:51 msgid "publication end date" msgstr "" -#: module/extensions/datepublisher.py:52 +#: module/extensions/datepublisher.py:53 msgid "Leave empty if the entry should stay active forever." msgstr "" -#: module/extensions/datepublisher.py:79 +#: module/extensions/datepublisher.py:80 msgid "visible from - to" msgstr "" -#: module/extensions/datepublisher.py:89 +#: module/extensions/datepublisher.py:90 msgid "Date-based publishing" msgstr "" @@ -426,213 +435,213 @@ msgstr "" msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:175 +#: module/extensions/translations.py:192 msgid "Edit translation" msgstr "" -#: module/extensions/translations.py:178 +#: module/extensions/translations.py:195 msgid "Create translation" msgstr "" -#: module/extensions/translations.py:183 +#: module/extensions/translations.py:200 msgid "translations" msgstr "" -#: module/medialibrary/forms.py:25 +#: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:57 +#: module/medialibrary/forms.py:64 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:57 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:76 +#: module/medialibrary/modeladmins.py:75 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:85 +#: module/medialibrary/modeladmins.py:84 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:87 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:92 +#: module/medialibrary/modeladmins.py:91 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:141 -#: templates/admin/feincms/page/page/item_editor.html:14 +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:90 +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 msgid "file size" msgstr "" -#: module/medialibrary/modeladmins.py:151 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 msgid "created" msgstr "" -#: module/medialibrary/modeladmins.py:170 module/medialibrary/models.py:87 +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 msgid "file type" msgstr "" -#: module/medialibrary/modeladmins.py:191 +#: module/medialibrary/modeladmins.py:184 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:203 +#: module/medialibrary/modeladmins.py:196 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:205 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:207 +#: module/medialibrary/modeladmins.py:200 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:46 +#: module/medialibrary/models.py:43 msgid "parent" msgstr "" -#: module/medialibrary/models.py:48 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "" -#: module/medialibrary/models.py:52 +#: module/medialibrary/models.py:49 msgid "category" msgstr "" -#: module/medialibrary/models.py:53 module/medialibrary/models.py:92 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "" -#: module/medialibrary/models.py:89 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "" -#: module/medialibrary/models.py:214 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "" -#: module/medialibrary/models.py:215 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "" -#: module/medialibrary/models.py:216 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:217 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:218 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:219 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:220 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "" -#: module/medialibrary/models.py:238 +#: module/medialibrary/models.py:236 msgid "description" msgstr "" -#: module/medialibrary/models.py:241 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "" -#: module/medialibrary/models.py:242 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "" -#: module/page/forms.py:113 +#: module/page/forms.py:118 msgid "This URL is already taken by an active page." msgstr "" -#: module/page/forms.py:131 +#: module/page/forms.py:136 msgid "This URL is already taken by another active page." msgstr "" -#: module/page/modeladmins.py:40 +#: module/page/modeladmins.py:41 msgid "Other options" msgstr "" -#: module/page/modeladmins.py:88 module/page/models.py:145 +#: module/page/modeladmins.py:89 module/page/models.py:145 msgid "in navigation" msgstr "" -#: module/page/modeladmins.py:99 +#: module/page/modeladmins.py:100 msgid "Add child page" msgstr "" -#: module/page/modeladmins.py:101 +#: module/page/modeladmins.py:102 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "" -#: module/page/modeladmins.py:129 +#: module/page/modeladmins.py:130 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:143 +#: module/page/modeladmins.py:144 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:158 +#: module/page/modeladmins.py:159 msgid "inherited" msgstr "" -#: module/page/modeladmins.py:162 +#: module/page/modeladmins.py:163 msgid "extensions" msgstr "" -#: module/page/modeladmins.py:166 module/page/models.py:179 +#: module/page/modeladmins.py:167 module/page/models.py:179 msgid "is active" msgstr "" @@ -683,18 +692,18 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:74 -#: module/page/extensions/navigation.py:94 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "" -#: module/page/extensions/navigation.py:96 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "" -#: module/page/extensions/navigation.py:109 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "" @@ -718,10 +727,6 @@ msgstr "" msgid "All content is inherited from this page if given." msgstr "" -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "" @@ -783,7 +788,7 @@ msgstr "" #, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -833,38 +838,38 @@ msgstr "" msgid "Save" msgstr "" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:22 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -873,16 +878,16 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" @@ -902,11 +907,11 @@ msgstr "" msgid "Filter" msgstr "" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "" -#: templates/admin/feincms/page/page/item_editor.html:26 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" @@ -931,15 +936,15 @@ msgstr "" msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:22 +#: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:25 +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "" diff --git a/feincms/locale/es/LC_MESSAGES/django.po b/feincms/locale/es/LC_MESSAGES/django.po index 3edb94dc1..89694b765 100644 --- a/feincms/locale/es/LC_MESSAGES/django.po +++ b/feincms/locale/es/LC_MESSAGES/django.po @@ -1,103 +1,113 @@ -# Traducción española de FeinCMS -# Copyright (C) 2009 proycon -# This file is distributed under the same license as the FeinCMS package. -# Maarten van Gompel (proycon) <proycon@anaproy.nl>, 2009. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# Maarten van Gompel (proycon) <proycon@anaproy.nl>, 2009. msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2010-09-20 20:24+0100\n" -"Last-Translator: antoni aloy <aaloy@apsl.net>\n" -"Language-Team: es <proycon@anaproy.nl>\n" -"Language: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Spanish\n" -"X-Poedit-SourceCharset: utf-8\n" -"X-Poedit-Country: SPAIN\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "plantilla" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "orden" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "idioma" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Todos" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Padre" -#: admin/filterspecs.py:95 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoría" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "título" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s ha sido movido a una nueva posición" -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "No entiendo la orden de movimiento" -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "acciones" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "¿Confirma la eliminación del elemento?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "contenido de la aplicación" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "contenidos de la aplicación" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "aplicación" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "activo" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Se podrán añadir nuevos comentarios" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "comentarios" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "público" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "privado" @@ -125,58 +135,74 @@ msgstr "formulario de contacto" msgid "contact forms" msgstr "formularios de contacto" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "archivo" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "archivos" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "imagen" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "leyenda" + +#: content/image/models.py:53 msgid "images" msgstr "imágenes" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "posición" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(sin leyenda)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "archivo de medios" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "archivos de medios" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "bloque" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "izquierda" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "derecha" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "tipo" @@ -188,20 +214,15 @@ msgstr "contenido crudo" msgid "raw contents" msgstr "contenidos crudos" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "texto" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "Ignorar los avisos de validación HTML" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " @@ -210,11 +231,15 @@ msgstr "" "La validación del HTML produjo %(count)d avisos. Por favor revisa el " "contenido actualizado de la parte inferior antes de continuar: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "texto" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "textos ricos" @@ -250,51 +275,51 @@ msgstr "feed RSS" msgid "RSS feeds" msgstr "feeds RSS" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "sección" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "secciones" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "plano" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "título de la fila" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "título de fila y columna" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tabla" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tablas" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "datos" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "plantilla de contenido" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "plantilla de contenidos" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "enlace de vídeo" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -302,35 +327,39 @@ msgstr "" "Debe ser un enlace a un vídeo de YouTube o Vimeo. Por ejemplo: http://www." "youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "vídeo" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "vídeos" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "publicado" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "También será usado para la navegación generada automáticamente." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "publicado en" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Se establecerá automáticamente cuando se marque en 'publicado'." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "entrada" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "entradas" @@ -339,32 +368,52 @@ msgid "tags" msgstr "etiquetas" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "traducción de" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Deja este campo vacío para las entradas en el idioma base." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "traducciones disponibles" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "fecha de creación" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "fecha de modificación" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "tipos de contenido" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "fecha de publicación" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "publicar hasta" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Si se deja en blanco la entrada permanecerá activa para siempre." + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "visible de - hasta" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "Publicación según la fecha" + #: module/extensions/featured.py:9 msgid "featured" msgstr "categorizado" @@ -393,148 +442,225 @@ msgstr "Será incluido antes de la meta descripción por defecto." msgid "Search engine optimization" msgstr "Optimización para motores de búsqueda" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Editar traducción" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Crear traducción" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "traducciones" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Pre-visualización" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "tamaño de archivo" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "creado en" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "tipo de archivo" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "información del archivo" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "padre" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "categoría" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "categorías" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "tipo de archivo" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "creado en" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "tamaño de archivo" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "información del archivo" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Imagen" -#: module/medialibrary/models.py:281 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "documento PDF" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Texto" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Texto rico" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binario" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "leyenda" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "descripción" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "traducción del archivo de media" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "traducciones del archivo de media" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Pre-visualización" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Esta URL ya está en uso en una página activa" -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Esta URL ya está en uno por otra página activa" -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "otras opciones" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" -msgstr "" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "en la navegación" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Añade una página hija" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Ver en sitio" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/models.py:256 -msgid "active" +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "heredado" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "extensiones" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" msgstr "activo" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "en la navegación" +#: module/page/models.py:138 +msgid "active" +msgstr "activo" -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "URL efectivo" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -543,82 +669,26 @@ msgstr "" "URL efectivo. Debe contener una '/' cuando se trata de un URL local. Este " "campo afecta la navegación y los URLs de las sub-páginas." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "redirección a" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "URL de destino para redirecciones automáticas." -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "URL en cache" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "página" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "páginas" -#: module/page/models.py:297 module/page/models.py:782 -msgid "is active" -msgstr "activo" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Esta URL ya está en uso en una página activa" - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Esta URL ya está en uno por otra página activa" - -#: module/page/models.py:674 -msgid "Other options" -msgstr "otras opciones" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Añade una página hija" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Ver en sitio" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "heredado" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "extensiones" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "fecha de publicación" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "publicar hasta" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Si se deja en blanco la entrada permanecerá activa para siempre." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "visible de - hasta" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "Publicación según la fecha" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "extracto" @@ -631,12 +701,12 @@ msgstr "Añade una breve descripción resumiendo el contenido de la página." msgid "Excerpt" msgstr "Extracto" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "extensión de navegación" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -644,7 +714,7 @@ msgstr "" "Selecciona el módulo que provee sub-páginas para esta pagina si necesitas " "personalizar la navegación." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "Extensión de navegación" @@ -668,10 +738,6 @@ msgstr "página direccionada" msgid "All content is inherited from this page if given." msgstr "Todo el contenido es heredado de esta página." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Página enlazada" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "título del contenido" @@ -695,18 +761,6 @@ msgstr "" msgid "Titles" msgstr "Títulos" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Editar traducción" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Crear traducción" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "traducciones" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -746,10 +800,10 @@ msgid "Really change template? <br />All changes are saved." msgstr "¿Deas cambiar la plantilla?<br /> Todos los cambios se guardarán." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "¿Deseas cambiar la plantilla? <br/>Todos los cambios se guardarán y el " "contenido desde <strong>%(source_regions)s</strong> se moverá a <strong>" @@ -791,42 +845,51 @@ msgstr "" msgid "Add new item" msgstr "Añadir nuevo elemento" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Guardar" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Terminar edición" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "editar" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "nuevo" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "arriba" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "abajo" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "borrar" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Página inicial" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -835,48 +898,47 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Atajos" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Colapsar el árbol" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Expandir el árbol" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Editar en el sitio" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "traducción del archivo de media" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -887,19 +949,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "categoría" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Sube un archivo ZIP:" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Enviar" @@ -936,117 +1001,5 @@ msgstr "Enviar" msgid "Thanks!" msgstr "¡Gracias!" -#~ msgid "rich text (ckeditor)" -#~ msgstr "texto rico (ckeditor)" - -#~ msgid "rich texts (ckeditor)" -#~ msgstr "textos ricos (ckeditor)" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Puedes editar la página copiada aquí abajo." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Acabas de reemplazar %s. Puedes continuar editando la que ahora es la " -#~ "página activa aquí abajo." - -#~ msgid "Move to" -#~ msgstr "Mover a" - -#~ msgid "Move" -#~ msgstr "Mover" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Reemplazar la página %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Crea una copia oculta de esta página" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "%(name)s \"%(obj)s\" fue modificado con éxito." - -#~ msgid "You may edit it again below." -#~ msgstr "Puedes volver a editar el elemento." - -#~ msgid "You may add another %s below." -#~ msgstr "Puedes añadir un nuevo %s aquí debajo." - -#~ msgid "Insert as child" -#~ msgstr "Incluir como descendente" - -#~ msgid "Insert before" -#~ msgstr "Incluir antes" - -#~ msgid "is visible" -#~ msgstr "es visible" - -#~ msgid "Video from unknown portal" -#~ msgstr "Vídeo de un portal desconocido" - -#~ msgid "Tree saved successfully." -#~ msgstr "Árbol guardado con éxito." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "No se puede ser dependiente de si mismo." - -#~ msgid "Delete" -#~ msgstr "Borrar" - -#~ msgid "Save and add another" -#~ msgstr "Guardar y añadir otro" - -#~ msgid "Save and continue editing" -#~ msgstr "Guardar y continuar a editar" - -#~ msgid "Properties" -#~ msgstr "Propiedades" - -#~ msgid "Move selected item to" -#~ msgstr "Mover elemento seleccionado para" - -#~ msgid "OK" -#~ msgstr "Vale" - -#~ msgid "Add %(name)s" -#~ msgstr "Añadir %(name)s" - -#~ msgid "Edit" -#~ msgstr "editar" - -#~ msgid "Database error" -#~ msgstr "Error de base de dados" - -#~ msgid "view content" -#~ msgstr "mostrar contenido" - -#~ msgid "" -#~ "Could not parse the view content because the view is excluded from " -#~ "infanta handling." -#~ msgstr "" -#~ "No fue posible leer el contenido de la vista, porque esta está excluida " -#~ "del tratamiento de infanta." - -#~ msgid "Placeholder for the %(viewname)s calling %(viewfunc)s" -#~ msgstr "Substituto para %(viewname)s, que llama %(viewfunc)s" - -#~ msgid "Placeholder for calling %(viewfunc)s" -#~ msgstr "Substituto para llamar %(viewfunc)s" - -#~ msgid "not active" -#~ msgstr "inactivo" - -#~ msgid "Save tree" -#~ msgstr "Guardar árbol" - -#~ msgid "%(icon)s (not active)" -#~ msgstr "%(icon)s (inactivo)" - -#~ msgid "%(icon)s (until %(from)s)" -#~ msgstr "%(icon)s (hasta %(from)s)" - -#~ msgid "%(icon)s (since %(to)s)" -#~ msgstr "%(icon)s (a partir de %(to)s)" - -#~ msgid "%(icon)s (%(from)s – %(to)s)" -#~ msgstr "%(icon)s (%(from)s – %(to)s)" +#~ msgid "Symlinked page" +#~ msgstr "Página enlazada" diff --git a/feincms/locale/fr/LC_MESSAGES/django.po b/feincms/locale/fr/LC_MESSAGES/django.po index 8c5897b43..b220fc29a 100644 --- a/feincms/locale/fr/LC_MESSAGES/django.po +++ b/feincms/locale/fr/LC_MESSAGES/django.po @@ -1,105 +1,112 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2009-10-17 22:00\n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" "Language-Team: LANGUAGE <LL@li.org>\n" -"Language: \n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Translated-Using: django-rosetta 0.4.7\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "modèle" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "séquence" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "langue" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Tous" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Parent" -#: admin/filterspecs.py:95 -#, fuzzy +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" -msgstr "catégorie" +msgstr "" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Changement %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "titre" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "actions" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Vraiment supprimer cet élément?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "contenu d'application" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "contenus d'application" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "application" -#: content/comments/models.py:28 -#, fuzzy +#: content/comments/models.py:24 msgid "enabled" -msgstr "tableau" +msgstr "" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:32 content/comments/models.py:33 -#, fuzzy +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" -msgstr "Contenu" +msgstr "" -#: content/comments/models.py:48 -#, fuzzy +#: content/comments/models.py:49 msgid "public" -msgstr "publié" +msgstr "" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "" @@ -127,58 +134,74 @@ msgstr "formulaire de contact" msgid "contact forms" msgstr "formulaires de contact" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "fichier" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "fichiers" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "image" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "légende" + +#: content/image/models.py:53 msgid "images" msgstr "images" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "position" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(aucune légende)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "fichier de média" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "fichiers de média" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "bloc" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "gauche" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "droite" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "type" @@ -190,31 +213,30 @@ msgstr "contenu cru" msgid "raw contents" msgstr "contenus crus" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "texte" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "texte" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "texte" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "textes" @@ -251,53 +273,51 @@ msgstr "Fil RSS" msgid "RSS feeds" msgstr "Fils RSS" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "section" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "sections" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "plaine" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "titre de la ligne" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "ligne de titre et de la colonne" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tableau" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tableaux" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "données" -#: content/template/models.py:62 -#, fuzzy +#: content/template/models.py:51 msgid "template content" -msgstr "contenu d'application" +msgstr "" -#: content/template/models.py:63 -#, fuzzy +#: content/template/models.py:52 msgid "template contents" -msgstr "contenus d'application" +msgstr "" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "lien du vidéo" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -305,36 +325,40 @@ msgstr "" "Cela devrait être un lien vers une vidéo YouTube ou Vimeo, à savoir: http://" "www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "vidéo" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "vidéos" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "publié" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Il est utilisé pour la navigation généré aussi." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "publié le" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" "Sera mis automatiquement une fois que vous cochez la case «publié» ci-dessus." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "entrée" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "entrées" @@ -343,43 +367,59 @@ msgid "tags" msgstr "mots-clé" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "traduction de" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 -#, fuzzy +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "" -"Laissez cette case vide pour les entrées dans la langue primaire (% s)." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "traductions disponibles" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "date de création" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "date de modification" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "types de contenu" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "date de la publication" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "date de termination de la publication" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Laissez vide si l'entrée doit rester active pour toujours." + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "visible de - à" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "" + #: module/extensions/featured.py:9 -#, fuzzy msgid "featured" -msgstr "crée" +msgstr "" #: module/extensions/featured.py:14 -#, fuzzy msgid "Featured" -msgstr "crée" +msgstr "" #: module/extensions/seo.py:9 msgid "meta keywords" @@ -401,151 +441,225 @@ msgstr "Ce sera ajouté à la description par défaut." msgid "Search engine optimization" msgstr "" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Modifier la traduction" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Créer traduction" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "traductions" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Prévisualiser" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "taille" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "crée" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "type de fichier" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "parent" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "télougou" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "catégorie" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "catégories" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "type de fichier" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "crée" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "taille" - -#: module/medialibrary/models.py:203 -#, fuzzy -msgid "file info" -msgstr "info du fichier" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "image" -#: module/medialibrary/models.py:281 -#, fuzzy +#: module/medialibrary/models.py:203 msgid "Video" -msgstr "vidéo" +msgstr "" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "Document PDF" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "texte" -#: module/medialibrary/models.py:286 -#, fuzzy +#: module/medialibrary/models.py:208 msgid "Rich Text" -msgstr "texte" +msgstr "" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Données binaires" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "légende" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "description" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "traductions du fichier de média" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "traductions des fichiers de média" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Prévisualiser" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Cette URL est déjà prise par une page active." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Cette URL est déjà pris par une autre page active." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Autres options" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "à la navigation" + +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Ajouter page enfant" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Voir sur le site" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "hérité" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "extensions" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" msgstr "" -#: module/page/models.py:256 +#: module/page/models.py:138 msgid "active" msgstr "actif" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "à la navigation" - -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "adresse URL forcée" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -555,83 +669,26 @@ msgstr "" "début et à la fin s'il s'agit d'une URL locale. Cela affecte la navigation " "et les adresses URL des sous-pages." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "rediriger à" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "URL pour redirections automatiques" -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "adresse URL temporairement enregistrée" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "page" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "pages" -#: module/page/models.py:297 module/page/models.py:782 -#, fuzzy -msgid "is active" -msgstr "actif" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Cette URL est déjà prise par une page active." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Cette URL est déjà pris par une autre page active." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "Autres options" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Ajouter page enfant" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Voir sur le site" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "hérité" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "extensions" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "date de la publication" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "date de termination de la publication" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Laissez vide si l'entrée doit rester active pour toujours." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "visible de - à" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "" @@ -644,12 +701,12 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "additif de la navigation" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -657,10 +714,9 @@ msgstr "" "Sélectionnez le module fournissant pages pour cette page si vous avez besoin " "de personnaliser la navigation." -#: module/page/extensions/navigation.py:112 -#, fuzzy +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" -msgstr "additif de la navigation" +msgstr "" #: module/page/extensions/relatedpages.py:13 msgid "Select pages that should be listed as related content." @@ -682,10 +738,6 @@ msgstr "" msgid "All content is inherited from this page if given." msgstr "Tout le contenu est hérité de cette page si donnée." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "titre du contenu" @@ -706,21 +758,8 @@ msgstr "" "Titre de la page pour fenêtre de navigateur. Même que le titre par défaut." #: module/page/extensions/titles.py:43 -#, fuzzy msgid "Titles" -msgstr "titre" - -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Modifier la traduction" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Créer traduction" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "traductions" +msgstr "" #: templates/admin/filter.html:3 #, python-format @@ -764,19 +803,18 @@ msgstr "" "enregistrées." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Réellement changer de modèle? <br /> Toutes les modifications sont " "enregistrées et le contenu <strong>de %(source_regions)s </strong> est " "déplacé vers <strong>%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 -#, fuzzy msgid "Hide" -msgstr "vidéo" +msgstr "" #: templates/admin/feincms/_messages_js.html:13 msgid "Show" @@ -791,9 +829,8 @@ msgid "Before" msgstr "" #: templates/admin/feincms/_messages_js.html:16 -#, fuzzy msgid "Insert new:" -msgstr "Insérer après" +msgstr "" #: templates/admin/feincms/content_editor.html:11 msgid "Region empty" @@ -811,42 +848,51 @@ msgstr "" msgid "Add new item" msgstr "Ajouter un autre" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Enregistrer" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "traiter" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "nouveau" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "vers le haut" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "vers le bas" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "supprimer" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Page d'accueil" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -855,49 +901,47 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Raccourcis" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Réduire l'arbre" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Développer l'arborescence" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filtre" -#: templates/admin/feincms/page/page/item_editor.html:9 -#, fuzzy +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" -msgstr "Voir sur le site" +msgstr "" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "traductions du fichier de média" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -908,19 +952,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "catégorie" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "" @@ -953,140 +1000,3 @@ msgstr "Envoyer" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Merci!" - -#, fuzzy -#~ msgid "rich text (ckeditor)" -#~ msgstr "texte" - -#, fuzzy -#~ msgid "rich texts (ckeditor)" -#~ msgstr "textes" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Vous pouvez continuer l'édition ci-dessous." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Vous avez remplacé% s. Vous pouvez continuer à modifier le page active ci-" -#~ "dessous." - -#, fuzzy -#~ msgid "Move" -#~ msgstr "supprimer" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Remplacer la page %(to_replace)s " - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Créer une copie cachée de cette page" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "L'objet %(name)s « %(obj)s » a été modifié avec succès." - -#~ msgid "You may edit it again below." -#~ msgstr "Vous pouvez continuer l'édition ci-dessous." - -#~ msgid "You may add another %s below." -#~ msgstr "Vous pouvez ajouter un autre %s ci-dessous." - -#~ msgid "Cut" -#~ msgstr "Couper" - -#~ msgid "Insert as child" -#~ msgstr "Insérer comme enfant" - -#~ msgid "Insert before" -#~ msgstr "Insérer avant" - -#~ msgid "is visible" -#~ msgstr "visible" - -#~ msgid "Video from unknown portal" -#~ msgstr "Vidéo de portail inconnu" - -#~ msgid "Tree saved successfully." -#~ msgstr "Structure arborescente enregistré avec succès." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "Impossible de faire un noeud d'un enfant de lui-même." - -#~ msgid "No item has been selected." -#~ msgstr "Aucun élément n'a été sélectionné." - -#~ msgid "Delete" -#~ msgstr "Supprimer" - -#~ msgid "Save and add another" -#~ msgstr "Enregistrer et ajouter un nouveau" - -#~ msgid "Save and continue editing" -#~ msgstr "Enregistrer et continuer les modifications" - -#~ msgid "Please correct the error below." -#~ msgid_plural "Please correct the errors below." -#~ msgstr[0] "SVP corrigez l'erreur ci-après" -#~ msgstr[1] "SVP corrigez les erreurs ci-après" - -#~ msgid "Properties" -#~ msgstr "Propriétés" - -#~ msgid "Move selected item to" -#~ msgstr "Déplacer l'élément choisie" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "Add %(name)s" -#~ msgstr "Ajout %(name)s" - -#~ msgid "Select an item on the left side if you want to edit it." -#~ msgstr "" -#~ "Sélectionnez un élément sur le côté gauche si vous voulez le modifier." - -#~ msgid "" -#~ "You can change the structure of the tree by drag-dropping elements. " -#~ "Please note that changes will be saved immediately. " -#~ msgstr "" -#~ "Vous pouvez changer la structure de l'arbre par glisser-déposer les " -#~ "éléments. S'il vous plaît noter que les modifications seront enregistrées " -#~ "immédiatement." - -#~ msgid "" -#~ "The context menu on the tree root and tree nodes provide you with " -#~ "additional modes of operation." -#~ msgstr "" -#~ "Le menu contextuel sur la racine d'arbre et de nœuds de l'arborescence " -#~ "vous fournir d'autres modes de fonctionnement." - -#~ msgid "Cannot remove this frame while inside this admin section." -#~ msgstr "" -#~ "Impossible de supprimer ce cadre tandis qu'à l'intérieur du présent " -#~ "article admin." - -#~ msgid "Reload" -#~ msgstr "Recharger" - -#~ msgid "Edit" -#~ msgstr "Modifier" - -#~ msgid "Database error" -#~ msgstr "Erreur de base de données" - -#~ msgid "view content" -#~ msgstr "contenu cru" - -#~ msgid "%(icon)s (not active)" -#~ msgstr "%(icon)s (pas active)" - -#~ msgid "%(icon)s (until %(from)s)" -#~ msgstr "%(icon)s (jusqu'à %(from)s)" - -#~ msgid "%(icon)s (since %(to)s)" -#~ msgstr "%(icon)s (depuis %(to)s)" - -#~ msgid "%(icon)s (%(from)s – %(to)s)" -#~ msgstr "%(icon)s (%(from)s – %(to)s)" - -#~ msgid "Save tree" -#~ msgstr "Enregistrer la structure arborescente" diff --git a/feincms/locale/hr/LC_MESSAGES/django.po b/feincms/locale/hr/LC_MESSAGES/django.po index ee6f1f689..6bc94e8f5 100644 --- a/feincms/locale/hr/LC_MESSAGES/django.po +++ b/feincms/locale/hr/LC_MESSAGES/django.po @@ -1,102 +1,114 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# Bojan Mihelac <bmihelac@mihelac.org>, 2010. # +# Translators: +# Bojan Mihelac <bmihelac@mihelac.org>, 2010. msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:20-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Bojan Mihelac <bmihelac@mihelac.org>\n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" "Language-Team: LANGUAGE <LL@li.org>\n" -"Language: \n" +"Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" -"%100==4 ? 2 : 3);\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "predložak" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "poredak" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "jezik" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Svi" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Nadređeni" -#: admin/filterspecs.py:95 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategorija" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Promjeni %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "naziv" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s je premještena na novu poziciju." -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "Uputa za premještanje nije uspješno interpretirana. " -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "akcije" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Stvarno izbrisati zapis?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "sadržaj aplikacije" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "sadržaji aplikacije" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "aplikacija" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "omogućeno" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Novi komentari mogu biti dodani" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "komentari" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "objavljeno" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "neobjavljeno" @@ -124,58 +136,74 @@ msgstr "kontaktni obrazac" msgid "contact forms" msgstr "kontaktni obrazci" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "datoteka" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "datoteke" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "slika" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "naslov" + +#: content/image/models.py:53 msgid "images" msgstr "slike" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "pozicija" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(bez naslova)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "medijska datoteka" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "medijske datoteke" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "blok" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "lijevo" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "desno" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "tip" @@ -187,20 +215,15 @@ msgstr "neformatirani sadržaj" msgid "raw contents" msgstr "neformatirani sadržaji" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "tekst" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "Zanemariti upozorenja HTML provjere" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " @@ -209,11 +232,15 @@ msgstr "" "HTML provjera je pokazala %(count)d upozorenja. Molimo pregledajte ažurirani " "sadržaj ispod prije nastavka: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "tekst" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "formatirani tekst" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "formatirani tekstovi" @@ -249,51 +276,51 @@ msgstr "RSS kanal" msgid "RSS feeds" msgstr "RSS kanali" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "sekcija" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "sekcije" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "jednostavno" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "naslovni redak" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "naslovni redak i kolona" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tablica" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tablice" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "podaci" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "sadržaj predloška" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "sadržaji predloška" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "link na video" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -301,35 +328,39 @@ msgstr "" "Polje treba sadržavati link na youtube ili vimeo video, i.e.: http://www." "youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "video" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "video zapisi" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "objavljeno" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Ovo se koristi i za generiranu navigaciju." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "objavljeno na" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Biti će automatski postavljeno kada označite `objavljeno` polje iznad." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "članak" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "članci" @@ -338,32 +369,53 @@ msgid "tags" msgstr "etikete" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "prijevod od" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Ostavite ovo prazno za zapise u primarnom jeziku." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "dostupni prijevodi" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "datum kreiranja" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "datum izmjene" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "tip sadržaja" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "datum objave" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "datum kraja objave" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "" +"Ostavite praznim ukoliko članak treba biti aktivan neograničeno vrijeme." + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "vidljiv od - do" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "Objava vezana na datum" + #: module/extensions/featured.py:9 msgid "featured" msgstr "istaknuti" @@ -392,150 +444,226 @@ msgstr "Ovo će biti dodano predefiniranom opisu." msgid "Search engine optimization" msgstr "Optimizacija za tražilice" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Uredi prijevod" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Kreiraj prijevod" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "prijevodi" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Pregled" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "veličina datoteke" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "kreiran" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "tip datoteke" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "informacije o datoteci" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "nadređeni" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "kategorija" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "kategorije" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "tip datoteke" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "kreiran" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "autorsko pravo" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "veličina datoteke" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "informacije o datoteci" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Slika" -#: module/medialibrary/models.py:281 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "PDF dokument" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Tekst" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Formatirani tekst" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binarni" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "naslov" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "opis" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "prijevod medijske datoteke" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "prijevodi medijske datoteke" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Pregled" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Ova adresa (URL) je već zauzeta aktivnom stranicom." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Ova adresa (URL) je već zauzeta drugom aktivnom stranicom." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Druge mogućnosti" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" -msgstr "" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "u navigaciji" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Dodaj podređenu stranicu" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Pogledaj na internetnim stranicama" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/models.py:256 +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "naslijeđeno" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "ekstenzije" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "je aktivna" + +#: module/page/models.py:138 msgid "active" msgstr "aktivan" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "u navigaciji" - -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "nadjačati URL" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -545,83 +673,26 @@ msgstr "" "početku i kraju ukoliko se odnosi na lokalnu adresu. Ovo se odnosi i na " "navigaciju i na adrese podstranica" -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "preusmjeriti na" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "Ciljna adresa (URL) za automatsko preusmjeravanje" -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "Keširana adresa (URL)" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "stranica" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "stranice" -#: module/page/models.py:297 module/page/models.py:782 -msgid "is active" -msgstr "je aktivna" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Ova adresa (URL) je već zauzeta aktivnom stranicom." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Ova adresa (URL) je već zauzeta drugom aktivnom stranicom." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "Druge mogućnosti" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Dodaj podređenu stranicu" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Pogledaj na internetnim stranicama" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "naslijeđeno" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "ekstenzije" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "datum objave" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "datum kraja objave" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "" -"Ostavite praznim ukoliko članak treba biti aktivan neograničeno vrijeme." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "vidljiv od - do" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "Objava vezana na datum" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "sažetak" @@ -634,12 +705,12 @@ msgstr "Dodajte kratak sažetak sadržaja ove stranice." msgid "Excerpt" msgstr "Sažetak" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "navigacijska ekstenzija" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -647,7 +718,7 @@ msgstr "" "Odaberite modul koji će dostaviti podstranice za ovu stranicu ukoliko je " "potrebno prilagoditi navigaciju." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "navigacijska ekstenzija" @@ -671,10 +742,6 @@ msgstr "simbolički povezana stranica" msgid "All content is inherited from this page if given." msgstr "Sav sadržaj je nasljeđen od ove stranice ukoliko je postavljena." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "simbolički povezana stranica" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "naslov sadržaja" @@ -697,18 +764,6 @@ msgstr "" msgid "Titles" msgstr "Nazivi" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Uredi prijevod" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Kreiraj prijevod" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "prijevodi" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -748,10 +803,10 @@ msgid "Really change template? <br />All changes are saved." msgstr "Zaista zamijeniti predložak? <br />Sve izmjene će biti spremljene." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Zaista zamijeniti predložak? <br />Sve izmjene su spremljene. i sadržaj iz " "<strong>%(source_regions)s</strong> će biti premješten u <strong>" @@ -793,42 +848,51 @@ msgstr "" msgid "Add new item" msgstr "Dodaj novi unos" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Spremi" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Prekini uređivanje" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "uredi" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "novi" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "gore" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "dolje" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "izbriši" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Home" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -837,48 +901,47 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Kratice" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Sažmi drvo" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Proširi drvo" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Uredi na stranicama" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "prijevod medijske datoteke" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -889,19 +952,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "kategorija" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Masovni prijenos ZIP datotekom:" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Pošalji" @@ -939,115 +1005,5 @@ msgstr "Potvrdi" msgid "Thanks!" msgstr "Hvala!" -#~ msgid "rich text (ckeditor)" -#~ msgstr "formatirani tekst (ckeditor)" - -#~ msgid "rich texts (ckeditor)" -#~ msgstr "formatirani tekstovi (ckeditor)" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Možete urediti kopiranu stranicu ispod." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Zamijenili ste %s. Možete nastaviti uređivati neaktivnu stranicu ispod." - -#~ msgid "Move to" -#~ msgstr "Premjesti u" - -#~ msgid "Move" -#~ msgstr "Premjesti" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Zamjeni stranicu %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Kreiraj skrivenu kopiju ove stranice" - -#~ msgid "Click save to replace the current content with this version" -#~ msgstr "Kliknite spremi da zamjenite trenutni sadržaj sa ovom verzijom" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "%(name)s \"%(obj)s\" je uspješno promijenjen." - -#~ msgid "You may edit it again below." -#~ msgstr "Možete urediti ponovno." - -#~ msgid "You may add another %s below." -#~ msgstr "Možete dodati još jedan %s." - -#~ msgid "Cut" -#~ msgstr "Izreži" - -#~ msgid "Insert as child" -#~ msgstr "Umetni kao podređen" - -#~ msgid "Video from unknown portal" -#~ msgstr "Video sa nepoznatog portala" - -#~ msgid "Tree saved successfully." -#~ msgstr "Drvo je uspješno spremljeno." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "Nije moguće napraviti objekt koji je podređen samom sebi." - -#~ msgid "No item has been selected." -#~ msgstr "Nijedan objekt nije odabran." - -#~ msgid "Add Child Page" -#~ msgstr "Dodaj podređenu stranicu" - -#~ msgid "Delete" -#~ msgstr "Izbriši" - -#~ msgid "Save and add another" -#~ msgstr "Spremi i dodaj novi unos" - -#~ msgid "Save and continue editing" -#~ msgstr "Spremi i nastavi uređivati" - -#~ msgid "Please correct the error below." -#~ msgid_plural "Please correct the errors below." -#~ msgstr[0] "Molimo ispravite navedenu grešku." -#~ msgstr[1] "Molimo ispravite navedene greške." -#~ msgstr[2] "Molimo ispravite navedene greške." - -#~ msgid "Properties" -#~ msgstr "Osobine" - -#~ msgid "Move selected item to" -#~ msgstr "Premjesti odabrani objekt na" - -#~ msgid "OK" -#~ msgstr "U redu" - -#~ msgid "Add %(name)s" -#~ msgstr "Dodaj %(name)s" - -#~ msgid "Select an item on the left side if you want to edit it." -#~ msgstr "Odaberite objekt sa lijeve strane ukoliko ga želite urediti." - -#~ msgid "" -#~ "You can change the structure of the tree by drag-dropping elements. " -#~ "Please note that changes will be saved immediately. " -#~ msgstr "" -#~ "Možete izmjeniti strukturu drveta koristeći drag and drop na elementima. " -#~ "Napomena: promijene će biti odmah zapamćene. " - -#~ msgid "" -#~ "The context menu on the tree root and tree nodes provide you with " -#~ "additional modes of operation." -#~ msgstr "" -#~ "Kontekstni menu na korijenu i čvorovima drveta omogućavaju dodatne načine " -#~ "rada." - -#~ msgid "Cannot remove this frame while inside this admin section." -#~ msgstr "" -#~ "Nije moguće obrisati ovaj frame dok ste u administracijskoj sekciji." - -#~ msgid "Reload" -#~ msgstr "Ponovno učitaj" - -#~ msgid "Edit" -#~ msgstr "Uredi" +#~ msgid "Symlinked page" +#~ msgstr "simbolički povezana stranica" diff --git a/feincms/locale/it/LC_MESSAGES/django.po b/feincms/locale/it/LC_MESSAGES/django.po index 6679784ce..73919853d 100644 --- a/feincms/locale/it/LC_MESSAGES/django.po +++ b/feincms/locale/it/LC_MESSAGES/django.po @@ -1,105 +1,112 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2009-10-17 22:15\n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" "Language-Team: LANGUAGE <LL@li.org>\n" -"Language: \n" +"Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Translated-Using: django-rosetta 0.4.7\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "template" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "ordinazione" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "lingua" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Tutto" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Parent" -#: admin/filterspecs.py:95 -#, fuzzy +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" -msgstr "categoria" +msgstr "" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Variazione% s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "Titolo" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "azioni" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Cancellare questa voce?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "applicazione" -#: content/comments/models.py:28 -#, fuzzy +#: content/comments/models.py:24 msgid "enabled" -msgstr "tavolo" +msgstr "" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:32 content/comments/models.py:33 -#, fuzzy +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" -msgstr "contenuto" +msgstr "" -#: content/comments/models.py:48 -#, fuzzy +#: content/comments/models.py:49 msgid "public" -msgstr "pubblicato" +msgstr "" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "" @@ -127,58 +134,74 @@ msgstr "forme di contatto" msgid "contact forms" msgstr "forme di contatto" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "file" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "files" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "image" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "caption" + +#: content/image/models.py:53 msgid "images" msgstr "immagini" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "Posizione" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(no caption)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "file multimediale" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "file multimediali" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "blocco" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "sinistra" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "destra" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "tipo" @@ -190,31 +213,30 @@ msgstr "raw contenuti" msgid "raw contents" msgstr "raw contenuti" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "testo" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "testo" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "rich text" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "" @@ -250,53 +272,51 @@ msgstr "RSS feed" msgid "RSS feeds" msgstr "Feed RSS" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "sezione" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "sezioni" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "plain" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "titolo di fila" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "riga del titolo e colonna" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tavolo" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tavoli" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "dati" -#: content/template/models.py:62 -#, fuzzy +#: content/template/models.py:51 msgid "template content" -msgstr "template" +msgstr "" -#: content/template/models.py:63 -#, fuzzy +#: content/template/models.py:52 msgid "template contents" -msgstr "raw contenuti" +msgstr "" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "video link" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -304,37 +324,41 @@ msgstr "" "Questo dovrebbe essere un link ad un video di YouTube o di Vimeo, vale a " "dire: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "video" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "video" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "pubblicato" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Questo viene utilizzato per la navigazione generato troppo." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "pubblicato il" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" "Verrà impostato automaticamente una volta che barrare la casella di " "controllo `` pubblicato in precedenza." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "" @@ -343,42 +367,59 @@ msgid "tags" msgstr "tags" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "traduzione di" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 -#, fuzzy +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." -msgstr "Lasciare vuoto questo campo per le voci in lingua primaria (% s)." +msgstr "" #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "traduzioni disponibili" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "data di creazione" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "tipi di contenuto" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "data di pubblicazione" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "data fine pubblicazione" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Lasciare vuoto se la voce dovrebbe rimanere attivo per sempre." + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "visibile da - a" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "" + #: module/extensions/featured.py:9 -#, fuzzy msgid "featured" -msgstr "creato" +msgstr "" #: module/extensions/featured.py:14 -#, fuzzy msgid "Featured" -msgstr "creato" +msgstr "" #: module/extensions/seo.py:9 msgid "meta keywords" @@ -400,150 +441,225 @@ msgstr "Questo sarà anteposto alla descrizione di default." msgid "Search engine optimization" msgstr "" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Modificare la traduzione" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Crea traduzione" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "traduzioni" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Anteprima" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "dimensione del file" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "creato" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "tipo di file" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "file info" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "genitore" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "categorie" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "tipo di file" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "creato" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "dimensione del file" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "file info" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Image" -#: module/medialibrary/models.py:281 -#, fuzzy +#: module/medialibrary/models.py:203 msgid "Video" -msgstr "video" +msgstr "" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "PDF document" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Testo" -#: module/medialibrary/models.py:286 -#, fuzzy +#: module/medialibrary/models.py:208 msgid "Rich Text" -msgstr "rich text" +msgstr "" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binary" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "caption" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "descrizione" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "traduzione di file multimediale" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "traduzioni di file multimediale" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Anteprima" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Questo URL è già stato preso da una pagina attiva." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Questo URL è già stato preso da un'altra pagina attiva." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Altre opzioni" + +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "in navigazione" + +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Aggiungi pagina figlio" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Vedi sul sito" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "ereditato" + +#: module/page/modeladmins.py:163 +msgid "extensions" msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" msgstr "" -#: module/page/models.py:256 +#: module/page/models.py:138 msgid "active" msgstr "attiva" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "in navigazione" - -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "override URL" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -553,83 +669,26 @@ msgstr "" "e alla fine se si tratta di un URL locale. Questo riguarda sia la " "navigazione e gli URL sottopagine '." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "reindirizzamento" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "URL di destinazione per i redirect automatico." -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "Cache URL" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "pagina" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "pagine" -#: module/page/models.py:297 module/page/models.py:782 -#, fuzzy -msgid "is active" -msgstr "attiva" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Questo URL è già stato preso da una pagina attiva." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Questo URL è già stato preso da un'altra pagina attiva." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "Altre opzioni" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Aggiungi pagina figlio" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Vedi sul sito" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "ereditato" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "data di pubblicazione" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "data fine pubblicazione" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Lasciare vuoto se la voce dovrebbe rimanere attivo per sempre." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "visibile da - a" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "" @@ -642,12 +701,12 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -655,7 +714,7 @@ msgstr "" "Selezionare il modulo che fornisce sottopagine per questa pagina, se avete " "bisogno di personalizzare la navigazione." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "" @@ -679,10 +738,6 @@ msgstr "" msgid "All content is inherited from this page if given." msgstr "Tutti i contenuti sono ereditate da questa pagina, se somministrata." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "il titolo del contenuto" @@ -703,21 +758,8 @@ msgstr "" "impostazione predefinita." #: module/page/extensions/titles.py:43 -#, fuzzy msgid "Titles" -msgstr "Titolo" - -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Modificare la traduzione" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Crea traduzione" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "traduzioni" +msgstr "" #: templates/admin/filter.html:3 #, python-format @@ -758,19 +800,18 @@ msgid "Really change template? <br />All changes are saved." msgstr "Davvero cambiare modello? <br /> Tutte le modifiche vengono salvate." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Davvero cambiare modello? <br /> Tutte le modifiche vengono salvate e il " "contenuto <strong>da %(source_regions)s </strong> è spostato <strong>" "%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 -#, fuzzy msgid "Hide" -msgstr "video" +msgstr "" #: templates/admin/feincms/_messages_js.html:13 msgid "Show" @@ -785,9 +826,8 @@ msgid "Before" msgstr "" #: templates/admin/feincms/_messages_js.html:16 -#, fuzzy msgid "Insert new:" -msgstr "Inserire prima" +msgstr "" #: templates/admin/feincms/content_editor.html:11 msgid "Region empty" @@ -805,42 +845,51 @@ msgstr "" msgid "Add new item" msgstr "Aggiungi nuovo elemento" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Salvare" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "modifica" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "nuovo" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "su" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "giù" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "rimuovere" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Casa" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -849,49 +898,47 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Scorciatoie" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filtro" -#: templates/admin/feincms/page/page/item_editor.html:9 -#, fuzzy +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" -msgstr "Vedi sul sito" +msgstr "" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "traduzione di file multimediale" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -902,19 +949,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "categoria" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "" @@ -947,107 +997,3 @@ msgstr "" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Grazie!" - -#, fuzzy -#~ msgid "rich text (ckeditor)" -#~ msgstr "rich text" - -#, fuzzy -#~ msgid "rich texts (ckeditor)" -#~ msgstr "rich text" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Si può modificare la pagina copiato qui sotto." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Hai sostituito %s. Si può continuare a modificare la pagina ora attiva al " -#~ "di sotto." - -#, fuzzy -#~ msgid "Move" -#~ msgstr "rimuovere" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Sostituire la pagina %(to_replace)s " - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Creare copia nascosta di questa pagina" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "Il %(name)s \" %(obj)s \" è stato modificato con successo." - -#~ msgid "You may edit it again below." -#~ msgstr "Si può modificare di nuovo sotto." - -#~ msgid "You may add another %s below." -#~ msgstr "Si può aggiungere un altro %s al di sotto." - -#~ msgid "Cut" -#~ msgstr "Tagliare" - -#~ msgid "Insert as child" -#~ msgstr "Inserisci come bambino" - -#~ msgid "is visible" -#~ msgstr "è visibile" - -#~ msgid "Video from unknown portal" -#~ msgstr "Video dal portale sconosciuti" - -#~ msgid "Tree saved successfully." -#~ msgstr "Albero salvato con successo." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "Non può fare un nodo di un bambino di se stesso." - -#~ msgid "No item has been selected." -#~ msgstr "Nessun elemento è stato selezionato." - -#~ msgid "Delete" -#~ msgstr "Eliminare" - -#~ msgid "Save and add another" -#~ msgstr "Salvare e aggiungere un altro" - -#~ msgid "Save and continue editing" -#~ msgstr "Salvare e continuare ad apportare modifiche" - -#~ msgid "Properties" -#~ msgstr "Immobili" - -#~ msgid "Move selected item to" -#~ msgstr "Sposta l'elemento selezionato" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "Add %(name)s" -#~ msgstr "Aggiungi %(name)s " - -#~ msgid "Select an item on the left side if you want to edit it." -#~ msgstr "Seleziona una voce sul lato sinistro, se si desidera modificarlo." - -#~ msgid "" -#~ "You can change the structure of the tree by drag-dropping elements. " -#~ "Please note that changes will be saved immediately. " -#~ msgstr "" -#~ "È possibile modificare la struttura dell'albero con drag-dropping " -#~ "elementi. Si prega di notare che le modifiche verranno salvate " -#~ "immediatamente." - -#~ msgid "" -#~ "The context menu on the tree root and tree nodes provide you with " -#~ "additional modes of operation." -#~ msgstr "" -#~ "Il menu di contesto, la radice dell'albero e nodi della struttura offrire " -#~ "ulteriori modalità di funzionamento." - -#~ msgid "Cannot remove this frame while inside this admin section." -#~ msgstr "" -#~ "Impossibile rimuovere questa cornice, mentre all'interno di questa " -#~ "sezione admin." - -#~ msgid "Edit" -#~ msgstr "Modifica" diff --git a/feincms/locale/nb/LC_MESSAGES/django.po b/feincms/locale/nb/LC_MESSAGES/django.po index ddb0b2704..7c8d6bc5b 100644 --- a/feincms/locale/nb/LC_MESSAGES/django.po +++ b/feincms/locale/nb/LC_MESSAGES/django.po @@ -1,100 +1,113 @@ -# Norsk bokmål oversettelse av FeinCMS -# Copyright (C) 2011 Håvard Grimelid -# This file is distributed under the same license as the FeinCMS package. -# Håvard Grimelid <h@grx.no>, 2011. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# Håvard Grimelid <h@grx.no>, 2011. msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"Last-Translator: Håvard Grimelid <h@grx.no>\n" -"Language-Team: nb <h@grx.no>\n" -"Language: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Revision-Date: 2011-03-09 13:20+0100\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "mal" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "sortering" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "språk" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Alle" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Forelder" -#: admin/filterspecs.py:95 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategori" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Endre %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "tittel" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s har blitt flytta til en ny posisjon." -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "Forstod ikke flytteinstruksjonen." -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "aktiviteter" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Slette objektet?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "applikasjonsinnhold" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "applikasjonsinnhold" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "applikasjon" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "på" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Nye kommentarer kan legges til" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "kommentarer" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "offentlig" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "ikke offentlig" @@ -122,58 +135,74 @@ msgstr "kontaktskjema" msgid "contact forms" msgstr "kontaktskjemaer" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "fil" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "filer" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "bilde" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "tittel" + +#: content/image/models.py:53 msgid "images" msgstr "bilder" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "posisjon" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(ingen tittel)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "mediafil" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "mediafiler" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "blokk" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "venstre" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "høyre" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "type" @@ -185,20 +214,15 @@ msgstr "råinnhold" msgid "raw contents" msgstr "råinnhold" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "tekst" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "Ignorer advarsler fra HTML-validering" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " @@ -207,11 +231,15 @@ msgstr "" "HTML-validering produserte %(count)d advarsler. Revider oppdatert innhold " "under før du fortsetter: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "tekst" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "rik tekst" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "rike tekster" @@ -247,51 +275,51 @@ msgstr "RSS-strøm" msgid "RSS feeds" msgstr "RSS-strømmer" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "avsnitt" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "avsnitt" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "enkel" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "tittelrad" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "tittelrad og kolonne" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tabell" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tabeller" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "data" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "malinnhold" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "malinnhold" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "videolink" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -299,35 +327,39 @@ msgstr "" "Dette må være en link til en YouTube- eller Vimeo-film. F. eks. http://www." "youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "video" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "videoer" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "publisert" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Denne vil også bli brukt for navigasjon." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "publisert på" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Blir satt automatisk så snart `publisert`-boksen blir kryssa av." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "innlegg" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "innlegg" @@ -336,32 +368,52 @@ msgid "tags" msgstr "merkelapper" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "oversettelse av" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "La denne være tom for innlegg på primærspråket." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "tilgjengelige oversettelser" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "opprettet dato" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "endret dato" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "innholdstyper" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "publiseringsdato" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "sluttdato for publisering" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "La denne være tom dersom siden alltid skal være aktiv." + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "synlig fra - til" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "Datobasert publisering" + #: module/extensions/featured.py:9 msgid "featured" msgstr "featured" @@ -390,148 +442,225 @@ msgstr "Dette vil bli lagt inn foran standard beskrivelse." msgid "Search engine optimization" msgstr "Søkemotoroptimalisering" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Rediger oversettelse" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Lag oversettelse" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "oversettelser" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Forhåndsvisning" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "filstørrelse" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "opprettet" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "filtype" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "filinfo" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "%d filer importert" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "Ingen inputfil gitt" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "forelder" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "kategori" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "kategorier" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "filtype" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "opprettet" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "filstørrelse" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "filinfo" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Bilde" -#: module/medialibrary/models.py:281 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Lyd" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "PDF-dokument" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Tekst" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Rik tekst" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "ZIP-arkiv" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binær" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "tittel" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "beskrivelse" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "mediafil-oversettelse" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "mediafil-oversettelser" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Forhåndsvisning" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Denne URL-en er allerede i bruk av en aktiv side." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Denne URL-en er allerede i bruk av annen en aktiv side." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Andre valg" + +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "i navigasjon" + +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Legg til underside" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Vis på nettsted" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" -msgstr "%d filer importert" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" +msgstr "" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" -msgstr "Ugyldig ZIP-fil: %s" +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "arvet" -#: module/medialibrary/models.py:448 -msgid "No input file given" -msgstr "Ingen inputfil gitt" +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "utvidelser" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "er aktiv" -#: module/page/models.py:256 +#: module/page/models.py:138 msgid "active" msgstr "aktiv" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "i navigasjon" - -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "overstyr URL" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -540,82 +669,26 @@ msgstr "" "Overstyr mål-URL. Inkluder skråstrek ved starten og ved slutten dersom det " "er en lokal URL. Dette gjelder både for navigasjons- og underside-URL-er." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "videresend til" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "Mål-URL for automatiske videresendelser." -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "Mellomlagret URL" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "side" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "sider" -#: module/page/models.py:297 module/page/models.py:782 -msgid "is active" -msgstr "er aktiv" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Denne URL-en er allerede i bruk av en aktiv side." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Denne URL-en er allerede i bruk av annen en aktiv side." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "Andre valg" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Legg til underside" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Vis på nettsted" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "arvet" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "utvidelser" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "publiseringsdato" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "sluttdato for publisering" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "La denne være tom dersom siden alltid skal være aktiv." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "synlig fra - til" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "Datobasert publisering" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "utdrag" @@ -628,12 +701,12 @@ msgstr "Legg til et kort sammendrag av innholdet på denne siden." msgid "Excerpt" msgstr "Utdrag" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "navigasjonsutvidelse" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -641,7 +714,7 @@ msgstr "" "Velg modulen som skal bidra med undersider til denne siden dersom du trenger " "å tilpasse navigasjonen." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "Navigasjonsutvidelse" @@ -665,10 +738,6 @@ msgstr "symbolsk linket side" msgid "All content is inherited from this page if given." msgstr "Dersom gitt, blir alt innhold blir arvet fra denne siden." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Symbolsk linket side" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "innholdstittel" @@ -689,18 +758,6 @@ msgstr "Sidetittel for nettleservinduet. Samme som tittel som standard." msgid "Titles" msgstr "Titler" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Rediger oversettelse" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Lag oversettelse" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "oversettelser" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -740,10 +797,10 @@ msgid "Really change template? <br />All changes are saved." msgstr "Endre mal? <br />Alle endringer blir lagret." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Endre mal? <br/> Alle endringer blir lagret og innhold fra <strong>" "%(source_regions)s</strong> blir flyttet til <strong>%(target_region)s</" @@ -785,92 +842,100 @@ msgstr "" msgid "Add new item" msgstr "Legg til nytt objekt" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Lagre" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Avslutt redigering" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "rediger" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "ny" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "opp" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "ned" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "fjern" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Hjem" -#: templates/admin/feincms/recover_form.html:10 -#, fuzzy, python-format +#: templates/admin/feincms/recover_form.html:11 +#, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "Legg til enda et %(verbose_name)s" +msgstr "" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 -#, fuzzy, python-format +#: templates/admin/feincms/revision_form.html:13 +#, python-format msgid "Revert %(verbose_name)s" -msgstr "Legg til enda et %(verbose_name)s" +msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Snarveier" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Slå sammen tre" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Utvid tre" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Rediger på nettsted" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "mediafil-oversettelse" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -881,19 +946,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "kategori" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Last opp ZIP-filer:" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Send" @@ -931,22 +999,5 @@ msgstr "Send inn" msgid "Thanks!" msgstr "Takk!" -#~ msgid "Could not access storage" -#~ msgstr "Fikk ikke tilgang til lagringsenheten" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Du kan redigere den kopierte siden under." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "%s er erstattet. Du kan fortsette å redigere den nå aktive siden under." - -#~ msgid "Remove" -#~ msgstr "Fjern" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Erstatt side %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Opprett skjult kopi av denne siden" +#~ msgid "Symlinked page" +#~ msgstr "Symbolsk linket side" diff --git a/feincms/locale/nl/LC_MESSAGES/django.po b/feincms/locale/nl/LC_MESSAGES/django.po index 66d502c0c..414871c54 100644 --- a/feincms/locale/nl/LC_MESSAGES/django.po +++ b/feincms/locale/nl/LC_MESSAGES/django.po @@ -1,100 +1,112 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # +# Translators: msgid "" msgstr "" -"Project-Id-Version: FeinCMS VERSION\n" +"Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2010-09-15 11:21+0200\n" -"Last-Translator: Bjorn Post <bjorn.post@gmail.com>\n" -"Language-Team: Dutch\n" -"Language: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "template" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "volgorde" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "taal" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Alle" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Ouder" -#: admin/filterspecs.py:95 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categorie" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "%s veranderen" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "titel" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s is verplaatst." -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "Begreep verplaats instructie niet" -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "acties" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Item echt verwijderen?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "applicatie content" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "applicatie contents" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "applicatie" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "actief" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Nieuwe reacties kunnen worden toegevoegd" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "reacties" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "gedeeld" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "niet gedeeld" @@ -122,58 +134,74 @@ msgstr "contactformulier" msgid "contact forms" msgstr "contactformulieren" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "bestand" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "bestanden" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "afbeelding" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "onderschrift" + +#: content/image/models.py:53 msgid "images" msgstr "afbeeldingen" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "positie" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(geen onderschrift)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "media-bestand" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "media-bestanden" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "blok" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "links" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "rechts" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "type" @@ -185,20 +213,15 @@ msgstr "Ruwe Inhoud" msgid "raw contents" msgstr "ruwe inhoud" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "tekst" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "Negeer de HTML validatie waarschuwingen" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " @@ -207,11 +230,15 @@ msgstr "" "HTML validatie leverde %(count)d waarschuwingen op. Kijk alsjeblieft de " "bijgewerkte content na voordat je verder gaat: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "tekst" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "opgemaakte tekst" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "opgemaakte teksten" @@ -247,51 +274,51 @@ msgstr "RSS feed" msgid "RSS feeds" msgstr "RSS feeds" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "sectie" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "secties" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "plat" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "titel rij" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "title rij en kolom" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tabel" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tabellen" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "data" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "template content" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "template contents" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "video link" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -299,36 +326,40 @@ msgstr "" "Dit moet een link naar een youtube of vimeo video zijn. Bijvoorbeeld: http://" "www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "video" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "videos" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "gepubliceerd" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Dit wordt ook gebruikt voor de gegenereerde navigatie." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "gepubliceerd op" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" "Wordt automatisch eenmalig ingesteld zodra `gepubliceerd` aangevinkt is." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "item" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "items" @@ -337,32 +368,52 @@ msgid "tags" msgstr "tags" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "vertaling van" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Laat dit veld leeg voor bijdragen in de hoofd-taal." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "Beschikbare vertalingen" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "gemaakt op" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "laatst gewijzigd op" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "content types" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "gepubliceerd op" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "gepubliceerd tot" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Leeglaten als het item voor altijd actief moet blijven." + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "zichtbaar van - tot" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "Datum-gebaseerde publicering" + #: module/extensions/featured.py:9 msgid "featured" msgstr "aanbevolen" @@ -391,148 +442,225 @@ msgstr "Deze beschrijving wordt voor in de standaard beschrijving ingevoegd." msgid "Search engine optimization" msgstr "Zoekmachine optimalisatie" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Wijzig vertaling" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Maak vertaling" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "vertalingen" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Voorbeeld" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "bestandsgrootte" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "gemaakt" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "bestandstype" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "bestandsinformatie" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "ouder" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "categorie" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "categorieën" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "bestandstype" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "gemaakt" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "bestandsgrootte" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "bestandsinformatie" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Afbeelding" -#: module/medialibrary/models.py:281 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "PDF document" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Tekst" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Opgemaakte Tekst" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binaire data" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "onderschrift" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "omschrijving" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "Mediabestand-vertaling" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "Mediabestand-vertalingen" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Voorbeeld" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Deze URL is al in gebruik door een actieve pagina." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Deze URL is al in gebruik door een andere actieve pagina." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Overige opties" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" -msgstr "" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "in navigatie" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Voeg subpagina toe" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Op de website bekijken" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/models.py:256 +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "geërfd" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "uitbreidingen" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "is actief" + +#: module/page/models.py:138 msgid "active" msgstr "actief" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "in navigatie" - -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "overschrijf URL" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -542,82 +670,26 @@ msgstr "" "weerszijden een / staan. Dit veld heeft betrekking op zowel de navigatie " "als de URLs van subpagina's." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "doorsturen naar" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "Eindpunt (URL) voor automatisch doorsturen." -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "URL uit cache" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "pagina" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "pagina's" -#: module/page/models.py:297 module/page/models.py:782 -msgid "is active" -msgstr "is actief" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Deze URL is al in gebruik door een actieve pagina." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Deze URL is al in gebruik door een andere actieve pagina." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "Overige opties" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Voeg subpagina toe" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Op de website bekijken" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "geërfd" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "uitbreidingen" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "gepubliceerd op" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "gepubliceerd tot" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Leeglaten als het item voor altijd actief moet blijven." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "zichtbaar van - tot" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "Datum-gebaseerde publicering" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "samenvatting" @@ -631,12 +703,12 @@ msgstr "" msgid "Excerpt" msgstr "Samenvatting" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "navigatie-uitbreiding" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -644,7 +716,7 @@ msgstr "" "Kies de module die subpagina's voor deze pagina definieert als je de " "navigatie wilt uitbreiden." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "Navigatie-uitbreiding" @@ -669,10 +741,6 @@ msgid "All content is inherited from this page if given." msgstr "" "Als dit ingesteld is, dan wordt de inhoud geleverd door de aangegeven pagina." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Verbonden pagina" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "content titel" @@ -694,18 +762,6 @@ msgstr "paginatitel voor het browservenster. Standaard gelijk aan de titel." msgid "Titles" msgstr "Titels" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Wijzig vertaling" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Maak vertaling" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "vertalingen" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -746,10 +802,10 @@ msgid "Really change template? <br />All changes are saved." msgstr "Template echt veranderen?<br />Alle wijzigingen zijn opgeslagen." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Template echt veranderen? <br />Alle wijzigingen zijn opgeslagen en de " "inhoud van <strong>%(source_regions)s</strong>is verplaatst naar <strong>" @@ -791,42 +847,51 @@ msgstr "" msgid "Add new item" msgstr "Nieuw item toevoegen" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Opslaan" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Stop met Wijzigen" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "wijzigen" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "nieuw" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "naar boven" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "naar onder" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "verwijderen" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Startpagina" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -835,48 +900,47 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Snelkoppelingen" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Alles dichtklappen" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Alles openklappen" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Op de website wijzigen" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "Mediabestand-vertaling" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -887,19 +951,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "categorie" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Opload meerdere bestanden tegelijk (zip-bestand):" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Verstuur" @@ -937,62 +1004,5 @@ msgstr "Verzenden" msgid "Thanks!" msgstr "Bedankt!" -#~ msgid "rich text (ckeditor)" -#~ msgstr "opgemaakte tekst (ckeditor)" - -#~ msgid "rich texts (ckeditor)" -#~ msgstr "opgemaakte teksten (ckeditor)" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Je kunt de gekopieerde pagina hieronder wijzigen." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Je hebt %s vervangen. Je kunt de nu actieve pagina hieronder verder " -#~ "wijzigen." - -#~ msgid "Move to" -#~ msgstr "Verplaats naar" - -#~ msgid "Move" -#~ msgstr "Verplaats" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Vervang pagina %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Maak verborgen kopie" - -#~ msgid "Add %(name)s" -#~ msgstr "Voeg %(name)s toe" - -#~ msgid "Select an item on the left side if you want to edit it." -#~ msgstr "Selecteer een item aan de linkerzijde als je het wilt wijzigen." - -#~ msgid "" -#~ "You can change the structure of the tree by drag-dropping elements. " -#~ "Please note that changes will be saved immediately. " -#~ msgstr "" -#~ "Je kunt de structuur veranderen door de elementen te verslepen. Alle " -#~ "wijzigingen worden direct opgeslagen." - -#~ msgid "" -#~ "The context menu on the tree root and tree nodes provide you with " -#~ "additional modes of operation." -#~ msgstr "" -#~ "Het contextmenu in de hoofdtak en takken van de boom voorzien je van " -#~ "extra functionaliteiten." - -#~ msgid "Cannot remove this frame while inside this admin section." -#~ msgstr "" -#~ "Kan dit frame niet verwijderen terwijl we in deze admin sectie zijn." - -#~ msgid "Reload" -#~ msgstr "Vernieuw" - -#~ msgid "Edit" -#~ msgstr "Wijzigen" - -#~ msgid "Delete" -#~ msgstr "Verwijderen" +#~ msgid "Symlinked page" +#~ msgstr "Verbonden pagina" diff --git a/feincms/locale/pl/LC_MESSAGES/django.po b/feincms/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 000000000..1fcecb367 --- /dev/null +++ b/feincms/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,994 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: FeinCMS\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: msmenzyk <msmenzyk@o2.pl>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2)\n" + +#: models.py:420 content/template/models.py:59 +msgid "template" +msgstr "szablon" + +#: models.py:551 +msgid "ordering" +msgstr "sortowanie" + +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 +msgid "language" +msgstr "język" + +#: admin/filterspecs.py:35 admin/filterspecs.py:70 +msgid "All" +msgstr "wszystko" + +#: admin/filterspecs.py:46 module/page/models.py:143 +msgid "Parent" +msgstr "Rodzic" + +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 +msgid "Category" +msgstr "Kategoria" + +#: admin/item_editor.py:157 +#, python-format +msgid "Change %s" +msgstr "Zmień %s" + +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 +msgid "title" +msgstr "tytuł" + +#: admin/tree_editor.py:404 +#, python-format +msgid "%s has been moved to a new position." +msgstr "%s został przesunięty" + +#: admin/tree_editor.py:408 +msgid "Did not understand moving instruction." +msgstr "Instrukcja przesunięcia nie jest zrozumiała." + +#: admin/tree_editor.py:417 +msgid "actions" +msgstr "akcje" + +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Usunąć?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 +msgid "application content" +msgstr "zawartość aplikacji" + +#: content/application/models.py:273 +msgid "application contents" +msgstr "application content" + +#: content/application/models.py:298 +msgid "application" +msgstr "aplikacja" + +#: content/comments/models.py:24 +msgid "enabled" +msgstr "aktywny" + +#: content/comments/models.py:24 +msgid "New comments may be added" +msgstr "Nowe komentarze mogą być dodane" + +#: content/comments/models.py:28 content/comments/models.py:29 +msgid "comments" +msgstr "komentarze" + +#: content/comments/models.py:49 +msgid "public" +msgstr "publiczne" + +#: content/comments/models.py:49 +msgid "not public" +msgstr "nie publiczne" + +#: content/contactform/models.py:18 +msgid "name" +msgstr "nazwa" + +#: content/contactform/models.py:19 +msgid "email" +msgstr "email" + +#: content/contactform/models.py:20 +msgid "subject" +msgstr "temat" + +#: content/contactform/models.py:23 content/raw/models.py:14 +msgid "content" +msgstr "zawartość" + +#: content/contactform/models.py:34 +msgid "contact form" +msgstr "formularz kontaktowy" + +#: content/contactform/models.py:35 +msgid "contact forms" +msgstr "formularze kontaktowe" + +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 +msgid "file" +msgstr "plik" + +#: content/file/models.py:26 +msgid "files" +msgstr "pliki" + +#: content/image/models.py:43 content/image/models.py:52 +msgid "image" +msgstr "zdjęcie" + +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "" + +#: content/image/models.py:53 +msgid "images" +msgstr "zdjęcia" + +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 +msgid "position" +msgstr "pozycja" + +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 +msgid "(no caption)" +msgstr "(brak napisu)" + +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 +msgid "media file" +msgstr "plik media" + +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 +msgid "media files" +msgstr "pliki media" + +#: content/medialibrary/models.py:139 +msgid "block" +msgstr "block" + +#: content/medialibrary/models.py:140 +msgid "left" +msgstr "lewa" + +#: content/medialibrary/models.py:141 +msgid "right" +msgstr "prawa" + +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 +msgid "type" +msgstr "typ" + +#: content/raw/models.py:18 +msgid "raw content" +msgstr "tekst niesformatowany" + +#: content/raw/models.py:19 +msgid "raw contents" +msgstr "teksty niesformatowane" + +#: content/richtext/models.py:22 +msgid "HTML Tidy" +msgstr "HTML Tidy" + +#: content/richtext/models.py:23 +msgid "Ignore the HTML validation warnings" +msgstr "Ignoruj ostrzeżenia o walidacji HMTL" + +#: content/richtext/models.py:47 +#, python-format +msgid "" +"HTML validation produced %(count)d warnings. Please review the updated " +"content below before continuing: %(messages)s" +msgstr "" + +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "tekst" + +#: content/richtext/models.py:85 +msgid "rich text" +msgstr "Obszar tekstowy (WYSIWYG)" + +#: content/richtext/models.py:86 +msgid "rich texts" +msgstr "Obszary tekstowe (WYSIWYG)" + +#: content/rss/models.py:21 +msgid "" +"The rss field is updated several times a day. A change in the title will " +"only be visible on the home page after the next feed update." +msgstr "" + +#: content/rss/models.py:22 +msgid "link" +msgstr "link" + +#: content/rss/models.py:23 +msgid "pre-rendered content" +msgstr "" + +#: content/rss/models.py:24 +msgid "last updated" +msgstr "ostatnio aktualizowany" + +#: content/rss/models.py:25 +msgid "max. items" +msgstr "maksymalna ilość" + +#: content/rss/models.py:29 +msgid "RSS feed" +msgstr "kanał RSS" + +#: content/rss/models.py:30 +msgid "RSS feeds" +msgstr "kanały RSS" + +#: content/section/models.py:41 +msgid "section" +msgstr "sekcja" + +#: content/section/models.py:42 +msgid "sections" +msgstr "sekcje" + +#: content/table/models.py:66 +msgid "plain" +msgstr "zwyczajny" + +#: content/table/models.py:67 +msgid "title row" +msgstr "tytuł" + +#: content/table/models.py:69 +msgid "title row and column" +msgstr "" + +#: content/table/models.py:75 +msgid "table" +msgstr "tablica" + +#: content/table/models.py:76 +msgid "tables" +msgstr "tablice" + +#: content/table/models.py:90 +msgid "data" +msgstr "data" + +#: content/template/models.py:51 +msgid "template content" +msgstr "tekst szablonu" + +#: content/template/models.py:52 +msgid "template contents" +msgstr "teksty szablonów" + +#: content/video/models.py:25 +msgid "video link" +msgstr "link video" + +#: content/video/models.py:26 +msgid "" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Umieść link do youtube.com lub vimeo.com, np. http://www.youtube.com/watch?" +"v=zmj1rpzDRZ0" + +#: content/video/models.py:30 +msgid "video" +msgstr "video" + +#: content/video/models.py:31 +msgid "videos" +msgstr "video" + +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 +msgid "published" +msgstr "opublikowany" + +#: module/blog/models.py:30 +msgid "This is used for the generated navigation too." +msgstr "" + +#: module/blog/models.py:33 +msgid "published on" +msgstr "opublikowany na" + +#: module/blog/models.py:34 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Zostanie automatycznie ustawione po kliknięciu \"opublikowany\" powyżej" + +#: module/blog/models.py:39 +msgid "entry" +msgstr "wpis" + +#: module/blog/models.py:40 +msgid "entries" +msgstr "wpisy" + +#: module/blog/extensions/tags.py:12 +msgid "tags" +msgstr "tagi" + +#: module/blog/extensions/translations.py:20 +#: module/extensions/translations.py:122 +msgid "translation of" +msgstr "tłumaczenie" + +#: module/blog/extensions/translations.py:23 +#: module/extensions/translations.py:125 +msgid "Leave this empty for entries in the primary language." +msgstr "" + +#: module/blog/extensions/translations.py:44 +#: templates/admin/feincms/item_editor.html:43 +msgid "available translations" +msgstr "dostępne tłumaczenia" + +#: module/extensions/changedate.py:32 +msgid "creation date" +msgstr "data utworzenia" + +#: module/extensions/changedate.py:33 +msgid "modification date" +msgstr "data modyfikacji" + +#: module/extensions/ct_tracker.py:136 +msgid "content types" +msgstr "typ treści" + +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "data publikacji" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "końcowa data publikacji" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Pozostaw puste jeśli nie chcesz określać końcowej daty publikacji" + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "widoczne od - do" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "Określanie okresu publikacji" + +#: module/extensions/featured.py:9 +msgid "featured" +msgstr "" + +#: module/extensions/featured.py:14 +msgid "Featured" +msgstr "" + +#: module/extensions/seo.py:9 +msgid "meta keywords" +msgstr "tagi meta - keywords" + +#: module/extensions/seo.py:10 +msgid "This will be prepended to the default keyword list." +msgstr "Zostanie dołączone z przodu listy tagów" + +#: module/extensions/seo.py:11 +msgid "meta description" +msgstr "tagi meta - description" + +#: module/extensions/seo.py:12 +msgid "This will be prepended to the default description." +msgstr "Zostanie dołączone z przodu listy tagów" + +#: module/extensions/seo.py:18 +msgid "Search engine optimization" +msgstr "Pola SEO " + +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Edytuj tłumaczenie" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Stwórz tłumaczenie" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "tłumaczenia" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "Dodaj zaznaczone pliki do kategorii" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Podgląd" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "rozmiar pliku" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "utworzony" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "typ pliku" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "informacje o pliku" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "zaimportowano %d plików" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "Brak wybranego pliku " + +#: module/medialibrary/models.py:43 +msgid "parent" +msgstr "rodzic" + +#: module/medialibrary/models.py:45 module/page/models.py:142 +msgid "slug" +msgstr "slug (wyświetlany adres)" + +#: module/medialibrary/models.py:49 +msgid "category" +msgstr "kategoria" + +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +msgid "categories" +msgstr "kategorie" + +#: module/medialibrary/models.py:87 +msgid "copyright" +msgstr "copyright" + +#: module/medialibrary/models.py:202 +msgid "Image" +msgstr "Zdjęcie" + +#: module/medialibrary/models.py:203 +msgid "Video" +msgstr "Video" + +#: module/medialibrary/models.py:204 +msgid "Audio" +msgstr "Audio" + +#: module/medialibrary/models.py:205 +msgid "PDF document" +msgstr "Dokument PDF" + +#: module/medialibrary/models.py:206 +msgid "Flash" +msgstr "Flash" + +#: module/medialibrary/models.py:207 +msgid "Text" +msgstr "Tekst" + +#: module/medialibrary/models.py:208 +msgid "Rich Text" +msgstr "Obszar tekstowy (WYSIWYG)" + +#: module/medialibrary/models.py:209 +msgid "Zip archive" +msgstr "Archiwum ZIP" + +#: module/medialibrary/models.py:210 +msgid "Microsoft Word" +msgstr "Microsoft Word" + +#: module/medialibrary/models.py:211 +msgid "Microsoft Excel" +msgstr "Microsoft Excel" + +#: module/medialibrary/models.py:212 +msgid "Microsoft PowerPoint" +msgstr "Microsoft PowerPoint" + +#: module/medialibrary/models.py:213 +msgid "Binary" +msgstr "Binarny" + +#: module/medialibrary/models.py:236 +msgid "description" +msgstr "opis" + +#: module/medialibrary/models.py:239 +msgid "media file translation" +msgstr "" + +#: module/medialibrary/models.py:240 +msgid "media file translations" +msgstr "" + +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "ten URL jest już używany przez aktywną stronę." + +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "ten URL jest już używany przez inną aktywną stronę." + +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Pozostałe opcje" + +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "W menu" + +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Dodaj podstronę" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Zobacz podgląd strony" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." +msgstr "" + +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" +msgstr "Nie masz wystarczających uprawnień aby edytować ten element" + +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "dziedziczone" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "rozszerzenia" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "czy jest aktywne" + +#: module/page/models.py:138 +msgid "active" +msgstr "aktywny" + +#: module/page/models.py:146 +msgid "override URL" +msgstr "nadpisz URL" + +#: module/page/models.py:147 +msgid "" +"Override the target URL. Be sure to include slashes at the beginning and at " +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" + +#: module/page/models.py:148 +msgid "redirect to" +msgstr "przekieruj do" + +#: module/page/models.py:149 +msgid "Target URL for automatic redirects." +msgstr "URL do automatycznych przekierowań" + +#: module/page/models.py:150 +msgid "Cached URL" +msgstr "" + +#: module/page/models.py:161 +msgid "page" +msgstr "strona" + +#: module/page/models.py:162 +msgid "pages" +msgstr "strony" + +#: module/page/extensions/excerpt.py:9 +msgid "excerpt" +msgstr "" + +#: module/page/extensions/excerpt.py:10 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" + +#: module/page/extensions/excerpt.py:12 +msgid "Excerpt" +msgstr "" + +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 +msgid "navigation extension" +msgstr "" + +#: module/page/extensions/navigation.py:102 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" + +#: module/page/extensions/navigation.py:115 +msgid "Navigation extension" +msgstr "" + +#: module/page/extensions/relatedpages.py:13 +msgid "Select pages that should be listed as related content." +msgstr "" + +#: module/page/extensions/relatedpages.py:20 +msgid "Related pages" +msgstr "Powiązane strony" + +#: module/page/extensions/sites.py:16 +msgid "Site" +msgstr "Strony" + +#: module/page/extensions/symlinks.py:15 +msgid "symlinked page" +msgstr "dowiązana strona" + +#: module/page/extensions/symlinks.py:16 +msgid "All content is inherited from this page if given." +msgstr "" + +#: module/page/extensions/titles.py:13 +msgid "content title" +msgstr "Tytuł treści" + +#: module/page/extensions/titles.py:14 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" + +#: module/page/extensions/titles.py:15 +msgid "page title" +msgstr "Tytuł strony" + +#: module/page/extensions/titles.py:16 +msgid "Page title for browser window. Same as title by default." +msgstr "" + +#: module/page/extensions/titles.py:43 +msgid "Titles" +msgstr "Tytuły" + +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Po %(filter_title)s " + +#: templates/admin/content/mediafile/init.html:9 +msgid "Search" +msgstr "Szukaj" + +#: templates/admin/feincms/_messages_js.html:4 +msgid "Really delete item?" +msgstr "Usunąć?" + +#: templates/admin/feincms/_messages_js.html:4 +msgid "Confirm to delete item" +msgstr "Potwierdź usunięcie" + +#: templates/admin/feincms/_messages_js.html:5 +msgid "Item deleted successfully." +msgstr "Element został usunięty" + +#: templates/admin/feincms/_messages_js.html:5 +msgid "Cannot delete item" +msgstr "Brak możliwości usunięcia elementu" + +#: templates/admin/feincms/_messages_js.html:6 +msgid "Cannot delete item, because it is parent of at least one other item." +msgstr "" +"Element nie może zostać usunięty ponieważ zawiera przynajmniej jeden element " +"podrzędny. Usuń wpierw elementy podrzędne." + +#: templates/admin/feincms/_messages_js.html:7 +msgid "Change template" +msgstr "Zmień szablon" + +#: templates/admin/feincms/_messages_js.html:8 +msgid "Really change template? <br />All changes are saved." +msgstr "Zmienić szablon? <br />Wszystkie zmiany zostały zachowane." + +#: templates/admin/feincms/_messages_js.html:9 +#, fuzzy, python-format +msgid "" +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +msgstr "" +"Zmienić szablon? <br />Wszystkie zmiany zostały zachowane, treść z <strong>" +"%(source_regions)s</strong> została przeniesiona do <strong>" +"%(target_region)s</strong>." + +#: templates/admin/feincms/_messages_js.html:12 +msgid "Hide" +msgstr "Ukryj" + +#: templates/admin/feincms/_messages_js.html:13 +msgid "Show" +msgstr "Pokaż" + +#: templates/admin/feincms/_messages_js.html:14 +msgid "After" +msgstr "Za" + +#: templates/admin/feincms/_messages_js.html:15 +msgid "Before" +msgstr "Przed" + +#: templates/admin/feincms/_messages_js.html:16 +msgid "Insert new:" +msgstr "Wstaw nowy:" + +#: templates/admin/feincms/content_editor.html:11 +msgid "Region empty" +msgstr "Pusty region" + +#: templates/admin/feincms/content_editor.html:15 +msgid "" +"Content from the parent site is automatically inherited. To override this " +"behaviour, add some content." +msgstr "" +"Treść ze strony nadrzędnej został automatycznie odziedziczony. Wstaw treść " +"aby nadpisać odziedziczoną wartość." + +#: templates/admin/feincms/content_editor.html:23 +msgid "Add new item" +msgstr "Dodaj nowy element" + +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "Dodaj następny %(verbose_name)s" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "Usuń" + +#: templates/admin/feincms/fe_editor.html:40 +msgid "Save" +msgstr "Zachowaj" + +#: templates/admin/feincms/fe_tools.html:28 +msgid "Stop Editing" +msgstr "Zakończ Edycję" + +#: templates/admin/feincms/fe_tools.html:33 +msgid "edit" +msgstr "edytuj" + +#: templates/admin/feincms/fe_tools.html:35 +msgid "new" +msgstr "nowy" + +#: templates/admin/feincms/fe_tools.html:36 +msgid "up" +msgstr "góra" + +#: templates/admin/feincms/fe_tools.html:37 +msgid "down" +msgstr "dół" + +#: templates/admin/feincms/fe_tools.html:38 +msgid "remove" +msgstr "usuń" + +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 +#: templates/admin/feincms/page/page/tree_editor.html:7 +msgid "Home" +msgstr "Główna" + +#: templates/admin/feincms/recover_form.html:11 +#, python-format +msgid "Recover deleted %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/recover_form.html:17 +msgid "Press the save button below to recover this version of the object." +msgstr "" + +#: templates/admin/feincms/revision_form.html:12 +msgid "History" +msgstr "Historia" + +#: templates/admin/feincms/revision_form.html:13 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/revision_form.html:24 +msgid "Press the save button below to revert to this version of the object." +msgstr "" + +#: templates/admin/feincms/tree_editor.html:32 +msgid "Shortcuts" +msgstr "" + +#: templates/admin/feincms/tree_editor.html:34 +msgid "Collapse tree" +msgstr "Zwiń drzewo" + +#: templates/admin/feincms/tree_editor.html:35 +msgid "Expand tree" +msgstr "Rozwiń drzewo" + +#: templates/admin/feincms/tree_editor.html:38 +msgid "Filter" +msgstr "Filtruj" + +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Edytuj na stronie" + +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Dodaj" + +#: templates/admin/medialibrary/add_to_category.html:5 +#: templates/admin/medialibrary/add_to_category.html:9 +msgid "Add media files to category" +msgstr "Dodaj pliki media do kategorii" + +#: templates/admin/medialibrary/add_to_category.html:11 +msgid "Select category to apply:" +msgstr "Wybierz kategorię:" + +#: templates/admin/medialibrary/add_to_category.html:17 +msgid "The following media files will be added to the selected category:" +msgstr "Następujące pliki media zostaną dodane do wybranej kategorii:" + +#: templates/admin/medialibrary/add_to_category.html:22 +msgid "Add to category" +msgstr "Dodaj do kategorii" + +#: templates/admin/medialibrary/add_to_category.html:23 +msgid "Cancel" +msgstr "Anuluj" + +#: templates/admin/medialibrary/mediafile/change_list.html:11 +msgid "Bulk upload a ZIP file:" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 +msgid "Send" +msgstr "Wyślij" + +#: templates/content/comments/default.html:10 +#, python-format +msgid "%(comment_count)s comments." +msgstr "" + +#: templates/content/comments/default.html:18 +#, python-format +msgid "" +"\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" + +#: templates/content/comments/default.html:28 +msgid "No comments." +msgstr "" + +#: templates/content/comments/default.html:36 +msgid "Post Comment" +msgstr "" + +#: templates/content/contactform/form.html:9 +msgid "Submit" +msgstr "Wyślij" + +#: templates/content/contactform/thanks.html:3 +msgid "Thanks!" +msgstr "Dziękuję!" + +#~ msgid "Symlinked page" +#~ msgstr "Dowiazana strona" diff --git a/feincms/locale/pt/LC_MESSAGES/django.po b/feincms/locale/pt/LC_MESSAGES/django.po index 19b859184..bb059ebb7 100644 --- a/feincms/locale/pt/LC_MESSAGES/django.po +++ b/feincms/locale/pt/LC_MESSAGES/django.po @@ -1,103 +1,113 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # <vfigueiro@gmail.com>, 2012. msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2012-03-09 16:47+0100\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" "PO-Revision-Date: 2012-06-30 21:51+0000\n" "Last-Translator: Vítor Figueiró <vfigueiro@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: models.py:419 content/template/models.py:59 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "modelo" -#: models.py:550 +#: models.py:551 msgid "ordering" msgstr "ordenação" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:102 +#: module/extensions/translations.py:119 msgid "language" msgstr "idioma" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Todos" -#: admin/filterspecs.py:57 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Ascendente" -#: admin/filterspecs.py:95 -#: templates/admin/medialibrary/mediafile/change_list.html:15 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:163 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:214 content/rss/models.py:20 -#: content/section/models.py:31 module/blog/models.py:30 -#: module/medialibrary/models.py:43 module/page/models.py:141 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 #: module/page/models.py:199 msgid "title" msgstr "título" -#: admin/tree_editor.py:389 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s foi movido para uma nova posição" -#: admin/tree_editor.py:393 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "A instrução para mover não foi entendida." -#: admin/tree_editor.py:402 +#: admin/tree_editor.py:417 msgid "actions" msgstr "acções" -#: content/application/models.py:264 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Confirma a eliminação do item?" + +#: admin/tree_editor.py:437 +#, fuzzy, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Recuperar %(verbose_name)s excluído" + +#: content/application/models.py:272 msgid "application content" msgstr "conteúdo de aplicação" -#: content/application/models.py:265 +#: content/application/models.py:273 msgid "application contents" msgstr "conteúdos de aplicação" -#: content/application/models.py:296 +#: content/application/models.py:298 msgid "application" msgstr "aplicação" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "habilitado" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Podem ser adicionados novos comentários" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "comentários" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "público" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "não público" @@ -126,7 +136,7 @@ msgid "contact forms" msgstr "formulários de contacto" #: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:86 +#: module/medialibrary/models.py:84 msgid "file" msgstr "ficheiro" @@ -146,7 +156,7 @@ msgstr "texto alternativo" msgid "Description of image" msgstr "Descrição da imagem" -#: content/image/models.py:48 module/medialibrary/models.py:237 +#: content/image/models.py:48 module/medialibrary/models.py:235 msgid "caption" msgstr "legenda" @@ -154,8 +164,8 @@ msgstr "legenda" msgid "images" msgstr "imagens" -#: content/image/models.py:79 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "posição" @@ -163,36 +173,36 @@ msgstr "posição" msgid "format" msgstr "formato" -#: content/medialibrary/models.py:38 +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(sem legenda)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:47 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:99 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "ficheiro multimédia" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:100 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "ficheiros multimédia" -#: content/medialibrary/models.py:130 +#: content/medialibrary/models.py:139 msgid "block" msgstr "bloco" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:140 msgid "left" msgstr "esquerda" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:141 msgid "right" msgstr "direita" -#: content/medialibrary/v2.py:49 content/section/models.py:52 -#: content/section/models.py:60 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "tipo" @@ -204,31 +214,32 @@ msgstr "conteúdo cru" msgid "raw contents" msgstr "conteúdos crus" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:32 -msgid "text" -msgstr "texto" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "Ignorar os avisos de validação do HTML" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo actualizado em baixo antes de continuar: %(messages)s " +msgstr "" +"A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo " +"actualizado em baixo antes de continuar: %(messages)s " -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "texto" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "textos ricos" @@ -236,7 +247,9 @@ msgstr "textos ricos" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só aparece no site após a actualização do feed RSS seguinte." +msgstr "" +"O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só " +"aparece no site após a actualização do feed RSS seguinte." #: content/rss/models.py:22 msgid "link" @@ -262,35 +275,35 @@ msgstr "feed RSS" msgid "RSS feeds" msgstr "feed RSS" -#: content/section/models.py:36 +#: content/section/models.py:41 msgid "section" msgstr "secção" -#: content/section/models.py:37 +#: content/section/models.py:42 msgid "sections" msgstr "secções" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "simples" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "linha de título" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "linha e coluna de título" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tabela" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tabelas" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "dados" @@ -308,9 +321,11 @@ msgstr "ligação de vídeo" #: content/video/models.py:26 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: " "http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" #: content/video/models.py:30 msgid "video" @@ -320,32 +335,33 @@ msgstr "vídeo" msgid "videos" msgstr "vídeos" -#: contrib/tagging.py:113 +#: contrib/tagging.py:117 msgid "Tagging" msgstr "Tagging" -#: module/blog/models.py:29 +#: module/blog/models.py:28 msgid "published" msgstr "publicado" -#: module/blog/models.py:31 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Isto também é usado para a navegação gerada automaticamente." -#: module/blog/models.py:34 +#: module/blog/models.py:33 msgid "published on" msgstr "publicado em" -#: module/blog/models.py:35 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Será definido automaticamente quando activar a caixa de verificação 'publicado' acima." +#: module/blog/models.py:34 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Será definido automaticamente quando activar a caixa de verificação " +"'publicado' acima." -#: module/blog/models.py:40 +#: module/blog/models.py:39 msgid "entry" msgstr "entrada" -#: module/blog/models.py:41 +#: module/blog/models.py:40 msgid "entries" msgstr "entradas" @@ -354,12 +370,12 @@ msgid "tags" msgstr "etiquetas" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "tradução de" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Deixe este campo em branco nas entradas no idioma original." @@ -368,11 +384,11 @@ msgstr "Deixe este campo em branco nas entradas no idioma original." msgid "available translations" msgstr "traduções disponíveis" -#: module/extensions/changedate.py:36 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "data de criação" -#: module/extensions/changedate.py:37 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "data de modificação" @@ -380,23 +396,23 @@ msgstr "data de modificação" msgid "content types" msgstr "tipos de conteúdo" -#: module/extensions/datepublisher.py:48 +#: module/extensions/datepublisher.py:49 msgid "publication date" msgstr "data de publicação" -#: module/extensions/datepublisher.py:50 +#: module/extensions/datepublisher.py:51 msgid "publication end date" msgstr "publicar até" -#: module/extensions/datepublisher.py:52 +#: module/extensions/datepublisher.py:53 msgid "Leave empty if the entry should stay active forever." msgstr "Deixe vazio se a entrada deve permanecer activa para sempre." -#: module/extensions/datepublisher.py:79 +#: module/extensions/datepublisher.py:80 msgid "visible from - to" msgstr "visível de - até" -#: module/extensions/datepublisher.py:89 +#: module/extensions/datepublisher.py:90 msgid "Date-based publishing" msgstr "Publicação baseada em datas" @@ -428,213 +444,218 @@ msgstr "Isto será inserido antes da descrição padrão." msgid "Search engine optimization" msgstr "Optimização para motor de busca" -#: module/extensions/translations.py:175 +#: module/extensions/translations.py:192 msgid "Edit translation" msgstr "Editar a tradução" -#: module/extensions/translations.py:178 +#: module/extensions/translations.py:195 msgid "Create translation" msgstr "Criar tradução" -#: module/extensions/translations.py:183 +#: module/extensions/translations.py:200 msgid "translations" msgstr "traduções" -#: module/medialibrary/forms.py:25 +#: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" msgstr "Isto criaria um ciclo na hierarquia" -#: module/medialibrary/forms.py:57 +#: module/medialibrary/forms.py:64 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "Não é possível sobrescrever com um tipo de ficheiro diferente (tentativa de substituir um %(old_ext)s com um %(new_ext)s)" +msgstr "" +"Não é possível sobrescrever com um tipo de ficheiro diferente (tentativa de " +"substituir um %(old_ext)s com um %(new_ext)s)" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:57 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." -msgstr[1] "%(count)d ficheiros multimédia adicionados com sucesso a %(category)s." +msgstr[0] "" +"%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." +msgstr[1] "" +"%(count)d ficheiros multimédia adicionados com sucesso a %(category)s." -#: module/medialibrary/modeladmins.py:76 +#: module/medialibrary/modeladmins.py:75 msgid "Add selected media files to category" msgstr "Adicionar os ficheiros multimédia seleccionados à categoria" -#: module/medialibrary/modeladmins.py:85 +#: module/medialibrary/modeladmins.py:84 #, python-format msgid "ZIP file exported as %s" msgstr "Ficheiro ZIP exportado como %s" -#: module/medialibrary/modeladmins.py:87 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file export failed: %s" msgstr "A exportação do ficheiro ZIP falhou: %s" -#: module/medialibrary/modeladmins.py:92 +#: module/medialibrary/modeladmins.py:91 msgid "Export selected media files as zip file" msgstr "Exportar os ficheiros multimédia seleccionados como ficheiro zip" -#: module/medialibrary/modeladmins.py:141 -#: templates/admin/feincms/page/page/item_editor.html:14 +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Antevisão" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:90 +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 msgid "file size" msgstr "tamanho do ficheiro" -#: module/medialibrary/modeladmins.py:151 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 msgid "created" msgstr "criado em" -#: module/medialibrary/modeladmins.py:170 module/medialibrary/models.py:87 +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 msgid "file type" msgstr "tipo de ficheiro" -#: module/medialibrary/modeladmins.py:191 +#: module/medialibrary/modeladmins.py:184 msgid "file info" msgstr "informação do ficheiro" -#: module/medialibrary/modeladmins.py:203 +#: module/medialibrary/modeladmins.py:196 #, python-format msgid "%d files imported" msgstr "%d ficheiros importados" -#: module/medialibrary/modeladmins.py:205 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "ZIP import failed: %s" msgstr "A importação do ficheiro ZIP falhou: %s" -#: module/medialibrary/modeladmins.py:207 +#: module/medialibrary/modeladmins.py:200 msgid "No input file given" msgstr "Não indicou o ficheiro de origem" -#: module/medialibrary/models.py:46 +#: module/medialibrary/models.py:43 msgid "parent" msgstr "ascendente" -#: module/medialibrary/models.py:48 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:52 +#: module/medialibrary/models.py:49 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:53 module/medialibrary/models.py:92 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "categorias" -#: module/medialibrary/models.py:89 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Imagem" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Áudio" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "Documento PDF" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:214 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Texto" -#: module/medialibrary/models.py:215 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Texto Rico" -#: module/medialibrary/models.py:216 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "Ficheiro zip" -#: module/medialibrary/models.py:217 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:218 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:219 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:220 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binário" -#: module/medialibrary/models.py:238 +#: module/medialibrary/models.py:236 msgid "description" msgstr "descrição" -#: module/medialibrary/models.py:241 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "tradução do ficheiro multimédia" -#: module/medialibrary/models.py:242 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "traduções do ficheiro multimédia" -#: module/page/forms.py:113 +#: module/page/forms.py:118 msgid "This URL is already taken by an active page." msgstr "Este URL já está tomado por uma página activa." -#: module/page/forms.py:131 +#: module/page/forms.py:136 msgid "This URL is already taken by another active page." msgstr "Este URL já está tomado por uma outra página activa." -#: module/page/modeladmins.py:40 +#: module/page/modeladmins.py:41 msgid "Other options" msgstr "outras opções" -#: module/page/modeladmins.py:88 module/page/models.py:145 +#: module/page/modeladmins.py:89 module/page/models.py:145 msgid "in navigation" msgstr "na navegação" -#: module/page/modeladmins.py:99 +#: module/page/modeladmins.py:100 msgid "Add child page" msgstr "Adicionar página descendente" -#: module/page/modeladmins.py:101 +#: module/page/modeladmins.py:102 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Ver no site" -#: module/page/modeladmins.py:129 +#: module/page/modeladmins.py:130 msgid "" "The content from the original translation has been copied to the newly " "created page." -msgstr "O conteúdo da tradução original foi copiado para a página recém-criada." +msgstr "" +"O conteúdo da tradução original foi copiado para a página recém-criada." -#: module/page/modeladmins.py:143 +#: module/page/modeladmins.py:144 msgid "You don't have the necessary permissions to edit this object" msgstr "Não possui as permissões necessárias para editar este objecto" -#: module/page/modeladmins.py:158 +#: module/page/modeladmins.py:159 msgid "inherited" msgstr "herdado" -#: module/page/modeladmins.py:162 +#: module/page/modeladmins.py:163 msgid "extensions" msgstr "extensões" -#: module/page/modeladmins.py:166 module/page/models.py:179 +#: module/page/modeladmins.py:167 module/page/models.py:179 msgid "is active" msgstr "activo" @@ -649,9 +670,11 @@ msgstr "URL efectivo" #: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "URL efectivo. Deve conter uma / no início e no fim, caso se trate de um URL local. Este campo determina a navegação e os URL's das sub-páginas." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"URL efectivo. Deve conter uma / no início e no fim, caso se trate de um URL " +"local. Este campo determina a navegação e os URL's das sub-páginas." #: module/page/models.py:148 msgid "redirect to" @@ -685,18 +708,20 @@ msgstr "Adicione um breve excerto que resuma o conteúdo desta página." msgid "Excerpt" msgstr "Excerto" -#: module/page/extensions/navigation.py:74 -#: module/page/extensions/navigation.py:94 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "extensão de navegação" -#: module/page/extensions/navigation.py:96 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "Seleccione o módulo que providencia as sub-páginas, caso necessite de personalizar a navegação." +msgstr "" +"Seleccione o módulo que providencia as sub-páginas, caso necessite de " +"personalizar a navegação." -#: module/page/extensions/navigation.py:109 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "Extensão de navegação" @@ -720,17 +745,14 @@ msgstr "página ligada" msgid "All content is inherited from this page if given." msgstr "O conteúdo é herdado desta página." -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Página ligada" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "título do conteúdo" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "A primeira linha é o título principal. Outras linhas serão sub-títulos." +msgstr "" +"A primeira linha é o título principal. Outras linhas serão sub-títulos." #: module/page/extensions/titles.py:15 msgid "page title" @@ -738,7 +760,8 @@ msgstr "título da página" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "Título da página para a janela do navegador. Se omitido assume o título." +msgstr "" +"Título da página para a janela do navegador. Se omitido assume o título." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -779,15 +802,18 @@ msgstr "Alterar o modelo" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." -msgstr "Confirma a alteração do modelo? <br />Todas as alterações serão guardadas." +msgstr "" +"Confirma a alteração do modelo? <br />Todas as alterações serão guardadas." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%(source_regions)s</strong> is moved to " -"<strong>%(target_region)s</strong>." -msgstr "Confirma que deseja alterar o modelo? <br />Todas as alterações serão guardadas e o conteúdo de <strong>%(source_regions)s</strong> será movido para <strong>%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +msgstr "" +"Confirma que deseja alterar o modelo? <br />Todas as alterações serão " +"guardadas e o conteúdo de <strong>%(source_regions)s</strong> será movido " +"para <strong>%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -836,58 +862,60 @@ msgstr "Remover" msgid "Save" msgstr "Guardar" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Parar de Editar" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "editar" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "novo" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "para cima" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "para baixo" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "remover" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:22 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Página inicial" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "Recuperar %(verbose_name)s excluído" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "Clique no botão 'Guardar' em baixo para recuperar esta versão do objecto." +msgstr "" +"Clique no botão 'Guardar' em baixo para recuperar esta versão do objecto." -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "Historial" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "Reverter %(verbose_name)s" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "Clique no botão 'Guardar' em baixo para reverter para esta versão do objecto." +msgstr "" +"Clique no botão 'Guardar' em baixo para reverter para esta versão do objecto." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -905,11 +933,11 @@ msgstr "Expandir a árvore" msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Editar no site" -#: templates/admin/feincms/page/page/item_editor.html:26 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "Adicionar" @@ -924,7 +952,8 @@ msgstr "Seleccione a categoria a aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "Os seguintes ficheiros multimédia serão adicionados à categoria seleccionada:" +msgstr "" +"Os seguintes ficheiros multimédia serão adicionados à categoria seleccionada:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -934,15 +963,15 @@ msgstr "Adicionar à categoria" msgid "Cancel" msgstr "Cancelar" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Enviar um ficheiro ZIP:" -#: templates/admin/medialibrary/mediafile/change_list.html:22 +#: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" msgstr "Sobrescrever" -#: templates/admin/medialibrary/mediafile/change_list.html:25 +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Enviar" @@ -955,9 +984,14 @@ msgstr "%(comment_count)s comentários." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s disse em " +"%(comment_submit_date)s<br />\n" " " -msgstr "\n %(comment_username)s disse em %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -974,3 +1008,6 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Obrigado!" + +#~ msgid "Symlinked page" +#~ msgstr "Página ligada" diff --git a/feincms/locale/pt_BR/LC_MESSAGES/django.po b/feincms/locale/pt_BR/LC_MESSAGES/django.po index 384bfe3e0..bae07c6d7 100644 --- a/feincms/locale/pt_BR/LC_MESSAGES/django.po +++ b/feincms/locale/pt_BR/LC_MESSAGES/django.po @@ -1,103 +1,113 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # +# Translators: +# Guilherme Gondim <semente+transifex@taurinus.org>, 2012. msgid "" msgstr "" -"Project-Id-Version: FienCMS\n" +"Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2010-09-15 23:34+0100\n" -"Last-Translator: Vítor Figueiró <vfigueiro@gmail.com>\n" -"Language-Team: pt-BR <vfigueiro@gmail.com>\n" -"Language: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Guilherme Gondim <semente@taurinus.org>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Portuguese\n" -"X-Poedit-Country: BRAZIL\n" -"X-Poedit-SourceCharset: utf-8\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "modelo" -#: models.py:553 +#: models.py:551 msgid "ordering" -msgstr "ordem" +msgstr "ordenação" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "idioma" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Todos" -#: admin/filterspecs.py:57 module/page/models.py:261 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Ascendente" -#: admin/filterspecs.py:95 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "título" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." -msgstr "%s foi movido para uma nova posição" +msgstr "%s foi movido para uma nova posição." -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "A instrução para mover não foi entendida." -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "ações" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Confirma a remoção do item?" + +#: admin/tree_editor.py:437 +#, fuzzy, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Recuperar %(verbose_name)s removido" + +#: content/application/models.py:272 msgid "application content" msgstr "conteúdo de aplicação" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "conteúdos de aplicação" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "aplicação" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "habilitado" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "Podem ser adicionados novos comentários" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "comentários" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "público" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "não público" @@ -125,58 +135,74 @@ msgstr "formulário de contato" msgid "contact forms" msgstr "formulários de contato" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "arquivo" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "arquivos" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "imagem" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "legenda" + +#: content/image/models.py:53 msgid "images" msgstr "imagens" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "posição" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(sem legenda)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "arquivo de mídia" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "arquivos de mídia" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "bloco" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "esquerda" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "direita" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "tipo" @@ -188,33 +214,32 @@ msgstr "conteúdo cru" msgid "raw contents" msgstr "conteúdos crus" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "texto" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "Ignorar os avisos de validação HTML" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -"A validação HTML produziu %(count)d avisos. Por favor reveja o conteúdo " -"atualizado em baixo antes de continuar: %(messages)s" +"A validação HTML produziu %(count)d avisos. Por favor, revise o conteúdo " +"atualizado abaixo antes de continuar: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "texto" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "textos ricos" @@ -223,8 +248,8 @@ msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." msgstr "" -"O feed RSS é atualizado várias vezes por dia. Uma alteração do título só " -"aparece no site após a atualização de feed RSS seguinte." +"O feed RSS é atualizado por várias vezes ao dia. Uma alteração do título só " +"será visível na página após a próxima atualização do feed." #: content/rss/models.py:22 msgid "link" @@ -250,89 +275,93 @@ msgstr "feed RSS" msgid "RSS feeds" msgstr "feeds RSS" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" -msgstr "secção" +msgstr "seção" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" -msgstr "secções" +msgstr "seções" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "simples" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" -msgstr "título da linha" +msgstr "linha de título" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "linha e coluna de título" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tabela" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tabelas" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "dados" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "conteúdo de modelo" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "conteúdos de modelo" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "ligação de vídeo" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" msgstr "" -"Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"Isto deve ser uma ligação para um vídeo do Youtube ou Vimeo, i.e.: http://" +"www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "vídeo" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "vídeos" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "publicado" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Isto também é usado para a navegação gerada automaticamente." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "publicado em" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" -"É definido automaticamente quando ativa a caixa de verificação 'publicado' " +"Será definido automaticamente assim que você ativar a caixa `publicado` " "acima." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "entrada" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "entradas" @@ -341,32 +370,52 @@ msgid "tags" msgstr "etiquetas" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "tradução de" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." -msgstr "Deixe este campo em branco nas entradas do idioma original." +msgstr "Deixe este campo em branco para entradas no idioma original." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "traduções disponíveis" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "data de criação" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "data de modificação" -#: module/extensions/ct_tracker.py:134 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "tipos de conteúdo" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "Otimização para motores de busca" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "publicar até" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Deixe em branco se a entrada deve ficar ativa para sempre." + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "visível de - até" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "Publicação baseada em datas" + #: module/extensions/featured.py:9 msgid "featured" msgstr "recomendado" @@ -377,7 +426,7 @@ msgstr "Recomendado" #: module/extensions/seo.py:9 msgid "meta keywords" -msgstr "palavras-chave meta" +msgstr "meta palavras-chave" #: module/extensions/seo.py:10 msgid "This will be prepended to the default keyword list." @@ -385,7 +434,7 @@ msgstr "Isto será inserido antes da lista de palavras-chave padrão." #: module/extensions/seo.py:11 msgid "meta description" -msgstr "descrição meta" +msgstr "meta descrição" #: module/extensions/seo.py:12 msgid "This will be prepended to the default description." @@ -393,265 +442,288 @@ msgstr "Isto será inserido antes da descrição padrão." #: module/extensions/seo.py:18 msgid "Search engine optimization" -msgstr "Otimização para motor de busca" +msgstr "Otimização para motores de busca" + +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Editar a tradução" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Criar tradução" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "traduções" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "Adicionado com sucesso %(count)d arquivo de mídia em %(category)s." +msgstr[1] "Adicionado com sucesso %(count)d arquivos de mídia em %(category)s." + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "Adicionar arquivos de mídia selecionados à categoria" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" -#: module/medialibrary/models.py:51 +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Pré-visualização" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "tamanho do arquivo" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "criado em" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "tipo de arquivo" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "informação do arquivo" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "%d arquivos importados" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "Nenhum arquivo de entrada fornecido" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "ascendente" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "categorias" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "tipo de arquivo" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "criado em" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -msgid "file size" -msgstr "tamanho do arquivo" - -#: module/medialibrary/models.py:203 -msgid "file info" -msgstr "informação do arquivo" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Imagem" -#: module/medialibrary/models.py:281 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Áudio" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "documento PDF" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Texto" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "Texto Rico" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "" +msgstr "Arquivo ZIP" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binário" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "legenda" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "descrição" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "tradução do arquivo de mídia" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "traduções do arquivo de mídia" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Pré-visualização" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Esta URL já está ocupada por uma página ativa." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Esta URL já está ocupada por outra página ativa." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Outras opções" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" -msgstr "" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "na navegação" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" -msgstr "" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Adicionar página descendente" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Ver no site" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/page/models.py:256 -msgid "active" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" +msgstr "Você não tem as permissões necessárias para editar este objeto" + +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "herdado" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "extensões" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" msgstr "ativo" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "na navegação" +#: module/page/models.py:138 +msgid "active" +msgstr "ativo" -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" -msgstr "URL efetivo" +msgstr "URL efetiva" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -"URL efetivo. Deve conter uma /, caso se trate de um URL local. Este campo " -"determina a navegação e os URL's das sub-páginas." +"Substitui a URL de destino. Certifique-se de incluir barras no início e no " +"final, se for uma URL local. Isso afeta tanto a navegação e URLs de " +"subpáginas." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "redirecionar para" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "URL de destino para redirecionamentos automáticos." -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "URL em cache" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "página" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "páginas" -#: module/page/models.py:297 module/page/models.py:782 -#, fuzzy -msgid "is active" -msgstr "ativo" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Este URL já está ocupado por uma página ativa." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Este URL já está ocupado por outra página ativa." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "outras opções" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Adicionar página descendente" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Ver no site" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "herdado" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "extensões" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "data de publicação" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "publicar até" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Deixe em branco se a entrada deve ficar ativa para sempre." - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "visível de - até" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "Publicação baseada em datas" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" -msgstr "excerto" +msgstr "trecho" #: module/page/extensions/excerpt.py:10 msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Adicione um breve excerto que sumarize o conteúdo desta página." +msgstr "Adicione um breve trecho que sumarize o conteúdo desta página." #: module/page/extensions/excerpt.py:12 msgid "Excerpt" -msgstr "Excerto" +msgstr "Trecho" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "extensão de navegação" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "Selecione o módulo que providencia sub-páginas." +msgstr "" +"Selecione o módulo que fornece sub-páginas para esta página se você precisa " +"personalizar a navegação." -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "Extensão de navegação" #: module/page/extensions/relatedpages.py:13 msgid "Select pages that should be listed as related content." -msgstr "Selecione páginas a listar como conteúdo relacionado." +msgstr "Selecione as páginas que devam ser listadas como conteúdo relacionado." #: module/page/extensions/relatedpages.py:20 msgid "Related pages" @@ -659,19 +731,15 @@ msgstr "Páginas relacionadas" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Site" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" -msgstr "página ligada" +msgstr "página de ligação" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "O conteúdo é herdado desta página." - -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Página ligada" +msgstr "O conteúdo é herdado desta página, se fornecida." #: module/page/extensions/titles.py:13 msgid "content title" @@ -680,7 +748,8 @@ msgstr "título do conteúdo" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." msgstr "" -"A primeira linha é o título principal. Outras linhas serão sub-títulos." +"A primeira linha é o título principal, as linhas subsequentes são sub-" +"títulos." #: module/page/extensions/titles.py:15 msgid "page title" @@ -689,24 +758,13 @@ msgstr "título da página" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." msgstr "" -"Título da página para a janela do navegador. Se omitido assume o título." +"Título da página para a janela do navegador. Por padrão, o mesmo que o " +"título." #: module/page/extensions/titles.py:43 msgid "Titles" msgstr "Títulos" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Editar a tradução" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Criar tradução" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "traduções" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -718,23 +776,23 @@ msgstr "Procurar" #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" -msgstr "Confirma a eliminação do item?" +msgstr "Confirma a remoção do item?" #: templates/admin/feincms/_messages_js.html:4 msgid "Confirm to delete item" -msgstr "Confirme para eliminar o item" +msgstr "Confirme para remover o item" #: templates/admin/feincms/_messages_js.html:5 msgid "Item deleted successfully." -msgstr "Item eliminado com sucesso." +msgstr "Item removido com sucesso." #: templates/admin/feincms/_messages_js.html:5 msgid "Cannot delete item" -msgstr "Impossível eliminar o item" +msgstr "Impossível remover o item" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Impossível eliminar o item, pois possui pelo menos um dependente." +msgstr "Impossível remover o item, pois ele possui pelo menos um dependente." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -743,13 +801,13 @@ msgstr "Alterar o modelo" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." msgstr "" -"Confirma a alteração do modelo? <br />Todas as alterações serão guardadas." +"Confirma a alteração do modelo? <br />Todas as alterações serão salvas." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Confirma a alteração do modelo? <br />As modificações serão gravadas e o " "conteúdo de <strong>%(source_regions)s</strong> será movido para <strong>" @@ -783,121 +841,137 @@ msgstr "Região vazia" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "O conteúdo é herdado da página ascendente, excepto se o indicar aqui." +msgstr "" +"O conteúdo é herdado automaticamente da página ascendente. Para mudar este " +"comportamento, adicione algum conteúdo." #: templates/admin/feincms/content_editor.html:23 msgid "Add new item" msgstr "Adicionar novo item" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "Adicionar mais um %(verbose_name)s" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "Remover" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Guardar" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" -msgstr "Parar de Editar" +msgstr "Parar Edição" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "editar" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "novo" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "para cima" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "para baixo" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "remover" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Página inicial" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Recuperar %(verbose_name)s removido" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." msgstr "" +"Pressione o botão de salvar abaixo para recuperar esta versão do objeto." -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "" +msgstr "Histórico" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Reverter %(verbose_name)s" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" +"Pressione o botão de salvar abaixo para reverter para esta versão do objeto." -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Atalhos" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" -msgstr "Colapsar a árvore" +msgstr "Contrair árvore" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" -msgstr "Expandir a árvore" +msgstr "Expandir árvore" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" -msgstr "Editar no sítio" +msgstr "Editar no site" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "" +msgstr "Adicionar" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "tradução do arquivo de mídia" +msgstr "página de ligação" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "" +msgstr "Selecione a categoria a aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" msgstr "" +"Os seguintes arquivos de mídia serão adicionados à categoria selecionada:" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "categoria" +msgstr "Adicionar à categoria" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "Cancelar" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" -msgstr "Enviar um arquivo ZIP:" +msgstr "Enviar em massa um arquivo ZIP:" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Enviar" @@ -935,141 +1009,5 @@ msgstr "Enviar" msgid "Thanks!" msgstr "Obrigado!" -#~ msgid "rich text (ckeditor)" -#~ msgstr "texto rico (ckeditor)" - -#~ msgid "rich texts (ckeditor)" -#~ msgstr "textos ricos (ckeditor)" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Pode voltar a editar a página copiada em baixo." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Substituiu %s. Pode continuar a editar a página em baixo, agora ativa." - -#~ msgid "Move to" -#~ msgstr "Mover para" - -#~ msgid "Move" -#~ msgstr "Mover" - -#~ msgid "Add %(name)s" -#~ msgstr "Adicionar %(name)s" - -#~ msgid "Select an item on the left side if you want to edit it." -#~ msgstr "Selecione um item à esquerda para o editar." - -#~ msgid "" -#~ "You can change the structure of the tree by drag-dropping elements. " -#~ "Please note that changes will be saved immediately. " -#~ msgstr "" -#~ "Pode alterar a estrutura da árvore arrastando elementos. Note que as " -#~ "alterações serão guardadas imediatamente." - -#~ msgid "" -#~ "The context menu on the tree root and tree nodes provide you with " -#~ "additional modes of operation." -#~ msgstr "" -#~ "O menu de contexto na raiz e nos ramos da árvore permite modos de " -#~ "operação adicionais." - -#~ msgid "Cannot remove this frame while inside this admin section." -#~ msgstr "" -#~ "É impossível remover esta moldura enquanto estiver dentro desta secção de " -#~ "admin." - -#~ msgid "Reload" -#~ msgstr "Recarregar" - -#~ msgid "Edit" -#~ msgstr "Editar" - -#~ msgid "Delete" -#~ msgstr "Eliminar" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Substituir a página %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Criar uma cópia oculta desta página" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "%(name)s \"%(obj)s\" foi modificado com sucesso." - -#~ msgid "You may edit it again below." -#~ msgstr "Pode voltar a editar o elemento." - -#~ msgid "You may add another %s below." -#~ msgstr "Pode adicionar um novo %s." - -#~ msgid "Insert as child" -#~ msgstr "Inserir como descendente" - -#~ msgid "Insert before" -#~ msgstr "Inserir antes" - -#~ msgid "is visible" -#~ msgstr "é visível" - -#~ msgid "Video from unknown portal" -#~ msgstr "Vídeo de um portal desconhecido" - -#~ msgid "Tree saved successfully." -#~ msgstr "Árvore guardada com sucesso." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "Um nó não pode ser dependente de si próprio." - -#~ msgid "Save and add another" -#~ msgstr "Guardar e adicionar outro" - -#~ msgid "Save and continue editing" -#~ msgstr "Guardar e continuar a editar" - -#~ msgid "Properties" -#~ msgstr "Propriedades" - -#~ msgid "Move selected item to" -#~ msgstr "Mover item selecionado para" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "Database error" -#~ msgstr "Erro de base de dados" - -#~ msgid "view content" -#~ msgstr "conteúdo da função" - -#~ msgid "" -#~ "Could not parse the view content because the view is excluded from " -#~ "infanta handling." -#~ msgstr "" -#~ "Não foi possível ler o conteúdo da vista, porque esta está excluída do " -#~ "tratamento de infanta." - -#~ msgid "Placeholder for the %(viewname)s calling %(viewfunc)s" -#~ msgstr "Substituto para %(viewname)s, que chama %(viewfunc)s" - -#~ msgid "Placeholder for calling %(viewfunc)s" -#~ msgstr "Substituto para chamar %(viewfunc)s" - -#~ msgid "not active" -#~ msgstr "inativo" - -#~ msgid "Save tree" -#~ msgstr "Guardar árvore" - -#~ msgid "%(icon)s (not active)" -#~ msgstr "%(icon)s (inactivo)" - -#~ msgid "%(icon)s (until %(from)s)" -#~ msgstr "%(icon)s (até %(from)s)" - -#~ msgid "%(icon)s (since %(to)s)" -#~ msgstr "%(icon)s (a partir de %(to)s)" - -#~ msgid "%(icon)s (%(from)s – %(to)s)" -#~ msgstr "%(icon)s (%(from)s – %(to)s)" +#~ msgid "Symlinked page" +#~ msgstr "Página de ligação" diff --git a/feincms/locale/ro/LC_MESSAGES/django.po b/feincms/locale/ro/LC_MESSAGES/django.po index d7d7ed43c..e811171fc 100644 --- a/feincms/locale/ro/LC_MESSAGES/django.po +++ b/feincms/locale/ro/LC_MESSAGES/django.po @@ -1,109 +1,115 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# GABRIEL KOVACS <kovacs.gabi@gmail.com>, 2010. # +# Translators: +# GABRIEL KOVACS <kovacs.gabi@gmail.com>, 2010. msgid "" msgstr "" -"Project-Id-Version: FienCMS\n" +"Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:19-0500\n" -"PO-Revision-Date: 2009-07-16 17:21+0100\n" -"Last-Translator: Gabriel Kovacs <kovacs.gabi@gmail.com>\n" -"Language-Team: ro <kovacs.gabi@gmail.com>\n" -"Language: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"Language-Team: Romanian (http://www.transifex.com/projects/p/feincms/" +"language/ro/)\n" +"Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Romanian\n" -"X-Poedit-SourceCharset: utf-8\n" -"X-Poedit-Country: ROMANIA\n" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?" +"2:1))\n" -#: models.py:421 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "șablon" -#: models.py:553 +#: models.py:551 msgid "ordering" msgstr "ordonare" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "limbă" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "" -#: admin/filterspecs.py:57 module/page/models.py:261 -#, fuzzy +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" -msgstr "părinte" +msgstr "" -#: admin/filterspecs.py:95 -#, fuzzy +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" -msgstr "categorie" +msgstr "" -#: admin/item_editor.py:150 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Modifică %s" -#: admin/tree_editor.py:218 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:32 -#: module/medialibrary/models.py:48 module/page/models.py:259 -#: module/page/models.py:338 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "titlu" -#: admin/tree_editor.py:396 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:400 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:409 +#: admin/tree_editor.py:417 msgid "actions" msgstr "acțiuni" -#: content/application/models.py:241 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Confirmți ștergerea obiectului?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" msgstr "conținutul aplicației" -#: content/application/models.py:242 +#: content/application/models.py:273 msgid "application contents" msgstr "conținuturile aplicației" -#: content/application/models.py:273 +#: content/application/models.py:298 msgid "application" msgstr "aplicație" -#: content/comments/models.py:28 -#, fuzzy +#: content/comments/models.py:24 msgid "enabled" -msgstr "tabel" +msgstr "" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:32 content/comments/models.py:33 -#, fuzzy +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" -msgstr "conținut" +msgstr "" -#: content/comments/models.py:48 -#, fuzzy +#: content/comments/models.py:49 msgid "public" -msgstr "publicat" +msgstr "" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "" @@ -131,58 +137,74 @@ msgstr "formular de contact" msgid "contact forms" msgstr "formulare de contact" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:90 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "fișier" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "fișiere" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "imagine" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "legendă" + +#: content/image/models.py:53 msgid "images" msgstr "imagini" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "poziție" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(fără legendă)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:48 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:102 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "fișier media" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:103 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "fișiere media" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:139 msgid "block" msgstr "blochează" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:140 msgid "left" msgstr "stânga" -#: content/medialibrary/models.py:133 +#: content/medialibrary/models.py:141 msgid "right" msgstr "dreapta" -#: content/medialibrary/v2.py:49 content/section/models.py:53 -#: content/section/models.py:61 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "tip" @@ -194,31 +216,30 @@ msgstr "conținut neformatat" msgid "raw contents" msgstr "conținuturi neformatate" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "text" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "text" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "text formatabil" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "texte formatabile" @@ -254,55 +275,51 @@ msgstr "flux RSS" msgid "RSS feeds" msgstr "fluxuri RSS" -#: content/section/models.py:37 -#, fuzzy +#: content/section/models.py:41 msgid "section" -msgstr "acțiuni" +msgstr "" -#: content/section/models.py:38 -#, fuzzy +#: content/section/models.py:42 msgid "sections" -msgstr "acțiuni" +msgstr "" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "simplu" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "titlu" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "titlu rând și coloană" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "tabel" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "tabele" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "data" -#: content/template/models.py:62 -#, fuzzy +#: content/template/models.py:51 msgid "template content" -msgstr "conținutul aplicației" +msgstr "" -#: content/template/models.py:63 -#, fuzzy +#: content/template/models.py:52 msgid "template contents" -msgstr "conținuturile aplicației" +msgstr "" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "legătură film" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -310,37 +327,41 @@ msgstr "" "Aceasta ar trebui să fie o legătură către un film de pe youtube sau vimeo, " "de ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "film" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "filme" -#: module/blog/models.py:31 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "publicat" -#: module/blog/models.py:33 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Aceasta este deasemenea folosită pentru navigarea generată." -#: module/blog/models.py:36 +#: module/blog/models.py:33 msgid "published on" msgstr "publicat la" -#: module/blog/models.py:37 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" "Va fi trimis automat în momentul in care bifați butonul `publicat` de mai " "sus." -#: module/blog/models.py:42 +#: module/blog/models.py:39 msgid "entry" msgstr "înregistrare" -#: module/blog/models.py:43 +#: module/blog/models.py:40 msgid "entries" msgstr "înregistrari" @@ -349,43 +370,59 @@ msgid "tags" msgstr "etichete" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "tradus de" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 -#, fuzzy +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." -msgstr "Lăsați gol pentru inregistrări in limba primară (%s)." +msgstr "" #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:45 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "traduceri disponibile" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "data creerii" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "data modificării" -#: module/extensions/ct_tracker.py:134 -#, fuzzy +#: module/extensions/ct_tracker.py:136 msgid "content types" -msgstr "titlu conținut" +msgstr "" + +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "data publicării" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "sfârșitul publicării" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "Lasă gol dacă înregistrarea ar trebui să fie activă întotdeauna" + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "vizibil de la - până la" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "" #: module/extensions/featured.py:9 -#, fuzzy msgid "featured" -msgstr "creat" +msgstr "" #: module/extensions/featured.py:14 -#, fuzzy msgid "Featured" -msgstr "creat" +msgstr "" #: module/extensions/seo.py:9 msgid "meta keywords" @@ -407,152 +444,226 @@ msgstr "Va fi inserată la descrierea predefinită." msgid "Search engine optimization" msgstr "" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "Modifică translatarea" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "Creează o translatare" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "translații" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Pre-vizualizare" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "creat" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "tipul fișierului" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "părinte" -#: module/medialibrary/models.py:53 module/page/models.py:260 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "categorie" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:96 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "categorii" -#: module/medialibrary/models.py:91 module/medialibrary/models.py:182 -msgid "file type" -msgstr "tipul fișierului" - -#: module/medialibrary/models.py:92 module/medialibrary/models.py:117 -msgid "created" -msgstr "creat" - -#: module/medialibrary/models.py:93 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:94 module/medialibrary/models.py:112 -#, fuzzy -msgid "file size" -msgstr "fișiere" - -#: module/medialibrary/models.py:203 -#, fuzzy -msgid "file info" -msgstr "fișier" - -#: module/medialibrary/models.py:280 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Imagine" -#: module/medialibrary/models.py:281 -#, fuzzy +#: module/medialibrary/models.py:203 msgid "Video" -msgstr "film" +msgstr "" -#: module/medialibrary/models.py:282 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "document PDF" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Text" -#: module/medialibrary/models.py:286 -#, fuzzy +#: module/medialibrary/models.py:208 msgid "Rich Text" -msgstr "text formatabil" +msgstr "" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Binar" -#: module/medialibrary/models.py:307 -msgid "caption" -msgstr "legendă" - -#: module/medialibrary/models.py:308 +#: module/medialibrary/models.py:236 msgid "description" msgstr "descriere" -#: module/medialibrary/models.py:311 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "traducere fișier media" -#: module/medialibrary/models.py:312 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "traduceri fișier media" -#: module/medialibrary/models.py:335 -msgid "Preview" -msgstr "Pre-vizualizare" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Acest URL este deja rezervat de către o pagină activă." -#: module/medialibrary/models.py:355 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Acest URL este deja rezervat de către o altă pagină activă." -#: module/medialibrary/models.py:373 -msgid "Add selected media files to category" -msgstr "" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Alte opțiuni" -#: module/medialibrary/models.py:440 -#, python-format -msgid "%d files imported" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "în navigare" + +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "Adaugă o pagină copil" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "Vezi pe site" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/medialibrary/models.py:442 -#, python-format -msgid "ZIP file invalid: %s" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/medialibrary/models.py:448 -msgid "No input file given" +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "moștenit" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "extensii" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" msgstr "" -#: module/page/models.py:256 +#: module/page/models.py:138 msgid "active" msgstr "activ" -#: module/page/models.py:263 module/page/models.py:711 -msgid "in navigation" -msgstr "în navigare" - -#: module/page/models.py:264 +#: module/page/models.py:146 msgid "override URL" msgstr "suprascrie URL" -#: module/page/models.py:265 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -561,83 +672,26 @@ msgstr "" "Suprascrie URL-ul țintă. Aveți grijă să scrieti / la început și la șfârșit " "dacă este un URL local.Aceasta afectează atât navigația cât și subpaginile." -#: module/page/models.py:266 +#: module/page/models.py:148 msgid "redirect to" msgstr "redirecționare către" -#: module/page/models.py:267 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "URL-ul țintă pentru redirectări automate." -#: module/page/models.py:268 +#: module/page/models.py:150 msgid "Cached URL" msgstr "URL în cache" -#: module/page/models.py:279 +#: module/page/models.py:161 msgid "page" msgstr "pagină" -#: module/page/models.py:280 +#: module/page/models.py:162 msgid "pages" msgstr "pagini" -#: module/page/models.py:297 module/page/models.py:782 -#, fuzzy -msgid "is active" -msgstr "activ" - -#: module/page/models.py:631 -msgid "This URL is already taken by an active page." -msgstr "Acest URL este deja rezervat de către o pagină activă." - -#: module/page/models.py:649 -msgid "This URL is already taken by another active page." -msgstr "Acest URL este deja rezervat de către o altă pagină activă." - -#: module/page/models.py:674 -msgid "Other options" -msgstr "Alte opțiuni" - -#: module/page/models.py:721 -msgid "Add child page" -msgstr "Adaugă o pagină copil" - -#: module/page/models.py:723 -msgid "View on site" -msgstr "Vezi pe site" - -#: module/page/models.py:759 -msgid "You don't have the necessary permissions to edit this object" -msgstr "" - -#: module/page/models.py:774 -msgid "inherited" -msgstr "moștenit" - -#: module/page/models.py:778 -msgid "extensions" -msgstr "extensii" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "data publicării" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "sfârșitul publicării" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "Lasă gol dacă înregistrarea ar trebui să fie activă întotdeauna" - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "vizibil de la - până la" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "" @@ -650,12 +704,12 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "navigare extinsă" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -663,10 +717,9 @@ msgstr "" "Selectați modulul care furnizează subpaginile pentru această pagină dacă " "doriți să personalizaţi." -#: module/page/extensions/navigation.py:112 -#, fuzzy +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" -msgstr "navigare extinsă" +msgstr "" #: module/page/extensions/relatedpages.py:13 msgid "Select pages that should be listed as related content." @@ -688,11 +741,6 @@ msgstr "legătură pagină" msgid "All content is inherited from this page if given." msgstr "Întreg conținutul este moștenit de la această pagină daca se dorește." -#: module/page/extensions/symlinks.py:30 -#, fuzzy -msgid "Symlinked page" -msgstr "legătură pagină" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "titlu conținut" @@ -712,21 +760,8 @@ msgstr "" "titlul paginii." #: module/page/extensions/titles.py:43 -#, fuzzy msgid "Titles" -msgstr "titlu" - -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Modifică translatarea" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Creează o translatare" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "translații" +msgstr "" #: templates/admin/filter.html:3 #, python-format @@ -768,19 +803,18 @@ msgid "Really change template? <br />All changes are saved." msgstr "Doriți ștergerea șablonului? <br />Toate modificarile au fost salvate." #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "Doriți ștergerea șablonului? <br />Toate schimbările au fost salvate și " "conținutul de la <strong>%(source_regions)s</strong> a fost mutat la <strong>" "%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 -#, fuzzy msgid "Hide" -msgstr "film" +msgstr "" #: templates/admin/feincms/_messages_js.html:13 msgid "Show" @@ -795,9 +829,8 @@ msgid "Before" msgstr "" #: templates/admin/feincms/_messages_js.html:16 -#, fuzzy msgid "Insert new:" -msgstr "Inssereaza după" +msgstr "" #: templates/admin/feincms/content_editor.html:11 msgid "Region empty" @@ -815,42 +848,51 @@ msgstr "" msgid "Add new item" msgstr "Adaugă un obiect nou" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Salvează" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "modifică" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "nou" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "sus" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "jos" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "scoate" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:16 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Acasă" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" msgstr "" @@ -859,49 +901,47 @@ msgstr "" msgid "Press the save button below to recover this version of the object." msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "Scurtături" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "Închide arborele" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "Deschide arborele" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "Filtrează" -#: templates/admin/feincms/page/page/item_editor.html:9 -#, fuzzy +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" -msgstr "Vezi pe site" +msgstr "" -#: templates/admin/feincms/page/page/item_editor.html:20 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 -#, fuzzy msgid "Add media files to category" -msgstr "traducere fișier media" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -912,19 +952,22 @@ msgid "The following media files will be added to the selected category:" msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 -#, fuzzy msgid "Add to category" -msgstr "categorie" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "" @@ -957,152 +1000,3 @@ msgstr "Trimite" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Mulțumesc!" - -#, fuzzy -#~ msgid "rich text (ckeditor)" -#~ msgstr "text formatabil" - -#, fuzzy -#~ msgid "rich texts (ckeditor)" -#~ msgstr "texte formatabile" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Puteți modifica pagina copiată mai jos." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "Ai înlocuit %s. Poți continua să modifici actuala pagină activă." - -#, fuzzy -#~ msgid "Move" -#~ msgstr "scoate" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Înlocuieste pagina %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Creează o copie ascunsă a paginii" - -#~ msgid "The %(name)s \"%(obj)s\" was changed successfully." -#~ msgstr "%(name)s \"%(obj)s\" a fost modificat cu succes." - -#~ msgid "You may edit it again below." -#~ msgstr "Poți să-l modifici din nou." - -#~ msgid "You may add another %s below." -#~ msgstr "Poți adăuga %s incă odata mai jos." - -#~ msgid "Cut" -#~ msgstr "Taie" - -#~ msgid "Insert as child" -#~ msgstr "Inserează ca și copil" - -#~ msgid "Insert before" -#~ msgstr "Inserează inainte" - -#~ msgid "is visible" -#~ msgstr "este vizibil" - -#~ msgid "Video from unknown portal" -#~ msgstr "Film de pe un portal necunoscut" - -#~ msgid "Tree saved successfully." -#~ msgstr "Arbore salvat cu succes." - -#~ msgid "Cannot make a node a child of itself." -#~ msgstr "Un nod nu poate fi făcut un copil al său." - -#~ msgid "No item has been selected." -#~ msgstr "Niciun obiect nu a fost selectat." - -#~ msgid "Delete" -#~ msgstr "Șterge" - -#~ msgid "Save and add another" -#~ msgstr "Salvează si adaugă alta" - -#~ msgid "Save and continue editing" -#~ msgstr "Salvează și continuă să modifici" - -#~ msgid "Please correct the error below." -#~ msgid_plural "Please correct the errors below." -#~ msgstr[0] "Vă rugăm să corectați eroarea de mai jos" -#~ msgstr[1] "Vă rugăm să corectați erorile de mai jos" - -#~ msgid "Properties" -#~ msgstr "Proprietăți" - -#~ msgid "Move selected item to" -#~ msgstr "Mută obiectul selectat la" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "Add %(name)s" -#~ msgstr "Adaugă %(name)s" - -#~ msgid "Select an item on the left side if you want to edit it." -#~ msgstr "Selectați un obiect din partea stângă dacă doriți să-l modificați" - -#~ msgid "" -#~ "You can change the structure of the tree by drag-dropping elements. " -#~ "Please note that changes will be saved immediately. " -#~ msgstr "" -#~ "Se poate schimba structura arborelui prin tragere și lăsare ( mutare ) a " -#~ "unui element. Luați notă faptul că aceste schimbări for fi salvate imediat" - -#~ msgid "" -#~ "The context menu on the tree root and tree nodes provide you with " -#~ "additional modes of operation." -#~ msgstr "" -#~ "Meniul contextual al arborelui rădăcină și ale nodurilor pune la " -#~ "dispoziție moduri de operare adiționale." - -#~ msgid "Cannot remove this frame while inside this admin section." -#~ msgstr "" -#~ "Acestă zonă nu se poate șterge atâta timp cât se află în această secțiune " -#~ "a administrării." - -#~ msgid "Reload" -#~ msgstr "Reîncarcă" - -#~ msgid "Edit" -#~ msgstr "Modifică" - -#~ msgid "Database error" -#~ msgstr "Eroare la baza de date" - -#~ msgid "view content" -#~ msgstr "vizualizează conținutul" - -#~ msgid "" -#~ "Could not parse the view content because the view is excluded from " -#~ "infanta handling." -#~ msgstr "" -#~ "Nu s-a putut parcurge view-ul deoarec view-ul este exclus din " -#~ "manipularea infantei." - -#~ msgid "Placeholder for the %(viewname)s calling %(viewfunc)s" -#~ msgstr "Cadru pentru %(viewname)s, care cheamă %(viewfunc)s" - -#~ msgid "Placeholder for calling %(viewfunc)s" -#~ msgstr "Cadru pentru chemarea %(viewfunc)s" - -#~ msgid "not active" -#~ msgstr "inactiv" - -#~ msgid "Save tree" -#~ msgstr "Salvează arborele" - -#~ msgid "%(icon)s (not active)" -#~ msgstr "%(icon)s (inactiv)" - -#~ msgid "%(icon)s (until %(from)s)" -#~ msgstr "%(icon)s (până la %(from)s)" - -#~ msgid "%(icon)s (since %(to)s)" -#~ msgstr "%(icon)s (de %(to)s)" - -#~ msgid "%(icon)s (%(from)s – %(to)s)" -#~ msgstr "%(icon)s (%(de la)s – %(până la)s)" diff --git a/feincms/locale/ru/LC_MESSAGES/django.po b/feincms/locale/ru/LC_MESSAGES/django.po index 7379e80c9..ab85f2006 100644 --- a/feincms/locale/ru/LC_MESSAGES/django.po +++ b/feincms/locale/ru/LC_MESSAGES/django.po @@ -1,105 +1,116 @@ -# Feincms Russian translation. +# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the feincms package. -# Mikhail Korobov <kmike84@gmail.com>, 2009. +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# Mikhail Korobov <kmike84@gmail.com>, 2009. msgid "" msgstr "" -"Project-Id-Version: \n" +"Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-03-23 11:30+0700\n" -"PO-Revision-Date: \n" -"Last-Translator: Mikhail Korobov <kmike84@gmail.com>\n" -"Language-Team: RUSSIAN\n" -"Language: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -#: models.py:419 content/template/models.py:59 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "шаблон" -#: models.py:550 +#: models.py:551 msgid "ordering" msgstr "сортировка" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:102 +#: module/extensions/translations.py:119 msgid "language" msgstr "язык" -#: admin/filterspecs.py:46 admin/filterspecs.py:84 +#: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" msgstr "Все" -#: admin/filterspecs.py:57 module/page/models.py:222 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "Родитель" -#: admin/filterspecs.py:95 -#: templates/admin/medialibrary/mediafile/change_list.html:15 +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Категория" -#: admin/item_editor.py:163 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "Изменить %s" -#: admin/tree_editor.py:215 content/rss/models.py:20 -#: content/section/models.py:31 module/blog/models.py:30 -#: module/medialibrary/models.py:55 module/page/models.py:220 -#: module/page/models.py:299 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "заголовок" -#: admin/tree_editor.py:385 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "Узел \"%s\" был перемещен на новое место." -#: admin/tree_editor.py:389 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "Перемещение не удалось. Непонятная команда." -#: admin/tree_editor.py:398 +#: admin/tree_editor.py:417 msgid "actions" msgstr "действия" -#: content/application/models.py:263 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "Вы уверены, что хотите удалить элемент?" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 msgid "application content" -msgstr "содержимое из приложения" +msgstr "" -#: content/application/models.py:264 +#: content/application/models.py:273 msgid "application contents" -msgstr "содержимое из приложения" +msgstr "" -#: content/application/models.py:295 +#: content/application/models.py:298 msgid "application" msgstr "приложение" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "включены" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" -msgstr "Можно добавить комментарии" +msgstr "" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" -msgstr "комментарии" +msgstr "" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" -msgstr "опубликовано" +msgstr "" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" -msgstr "не опубликовано" +msgstr "" #: content/contactform/models.py:18 msgid "name" @@ -115,7 +126,7 @@ msgstr "тема" #: content/contactform/models.py:23 content/raw/models.py:14 msgid "content" -msgstr "содержимое" +msgstr "содержание" #: content/contactform/models.py:34 msgid "contact form" @@ -125,106 +136,117 @@ msgstr "форма обратной связи" msgid "contact forms" msgstr "формы обратной связи" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:105 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "файл" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "файлы" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" -msgstr "изображение" +msgstr "картинка" + +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" -#: content/image/models.py:29 +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "подпись" + +#: content/image/models.py:53 msgid "images" -msgstr "изображения" +msgstr "картинки" -#: content/image/models.py:42 content/medialibrary/models.py:105 -#: content/medialibrary/models.py:113 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "расположение" -#: content/medialibrary/models.py:38 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(без подписи)" -#: content/medialibrary/models.py:87 content/medialibrary/models.py:101 -#: content/medialibrary/models.py:111 content/medialibrary/v2.py:44 -#: content/section/models.py:47 module/medialibrary/fields.py:45 -#: module/medialibrary/models.py:118 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" -msgstr "медиа файл" +msgstr "" -#: content/medialibrary/models.py:88 content/medialibrary/v2.py:45 -#: module/medialibrary/models.py:119 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" -msgstr "медиа файлы" +msgstr "" -#: content/medialibrary/models.py:130 +#: content/medialibrary/models.py:139 msgid "block" msgstr "блок" -#: content/medialibrary/models.py:131 +#: content/medialibrary/models.py:140 msgid "left" msgstr "слева" -#: content/medialibrary/models.py:132 +#: content/medialibrary/models.py:141 msgid "right" msgstr "справа" -#: content/medialibrary/v2.py:49 content/section/models.py:52 -#: content/section/models.py:60 content/table/models.py:81 +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 msgid "type" msgstr "тип" #: content/raw/models.py:18 msgid "raw content" -msgstr "сырые данные" +msgstr "" #: content/raw/models.py:19 msgid "raw contents" -msgstr "сырые данные" - -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:32 -msgid "text" -msgstr "текст" +msgstr "" -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" -msgstr "Игнорировать предупреждения о некорректном HTML" +msgstr "" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -"Во время проверки HTML обнаружено %(count)d предупреджений. Перед тем как " -"продолжить обратите внимание на следующее: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "текст" + +#: content/richtext/models.py:85 msgid "rich text" -msgstr "форматированный текст" +msgstr "" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" -msgstr "форматированный тексты" +msgstr "" #: content/rss/models.py:21 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." msgstr "" -"Данное поле обновляется несколько раз в день. Изменения в названии на " -"домашней странице будут видны только после следующегог обновления" #: content/rss/models.py:22 msgid "link" @@ -250,45 +272,45 @@ msgstr "" msgid "RSS feeds" msgstr "" -#: content/section/models.py:36 +#: content/section/models.py:41 msgid "section" -msgstr "секция" +msgstr "" -#: content/section/models.py:37 +#: content/section/models.py:42 msgid "sections" -msgstr "секции" +msgstr "" -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" -msgstr "заголовок строки" +msgstr "" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" -msgstr "заголовок строки и столбца" +msgstr "" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "таблица" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "таблицы" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "данные" #: content/template/models.py:51 msgid "template content" -msgstr "содержимое шаблона" +msgstr "" #: content/template/models.py:52 msgid "template contents" -msgstr "содержимое шаблона" +msgstr "" #: content/video/models.py:25 msgid "video link" @@ -310,33 +332,33 @@ msgstr "видео" msgid "videos" msgstr "видео" -#: contrib/tagging.py:113 +#: contrib/tagging.py:117 msgid "Tagging" msgstr "" -#: module/blog/models.py:29 +#: module/blog/models.py:28 msgid "published" msgstr "опубликовано" -#: module/blog/models.py:31 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "Используется также в сгенерированно навигации." -#: module/blog/models.py:34 +#: module/blog/models.py:33 msgid "published on" msgstr "опубликовано" -#: module/blog/models.py:35 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" "Будет установлено автоматически, как только Вы отметите пункт \"опубликовано" "\" выше." -#: module/blog/models.py:40 +#: module/blog/models.py:39 msgid "entry" msgstr "запись" -#: module/blog/models.py:41 +#: module/blog/models.py:40 msgid "entries" msgstr "записи" @@ -345,386 +367,380 @@ msgid "tags" msgstr "теги" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" -msgstr "перевод для" +msgstr "" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "Оставьте поле пустым для записей на основном языке (%s)." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:40 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "доступные переводы" -#: module/extensions/changedate.py:36 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "дата создания" -#: module/extensions/changedate.py:37 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "дата изменения" #: module/extensions/ct_tracker.py:136 msgid "content types" -msgstr "тип данных" +msgstr "" -#: module/extensions/datepublisher.py:48 +#: module/extensions/datepublisher.py:49 msgid "publication date" msgstr "дата публикации" -#: module/extensions/datepublisher.py:50 +#: module/extensions/datepublisher.py:51 msgid "publication end date" msgstr "дата окончания публикации" -#: module/extensions/datepublisher.py:52 +#: module/extensions/datepublisher.py:53 msgid "Leave empty if the entry should stay active forever." msgstr "Оставьте поле пустым, если запись должна оставаться активной навсегда." -#: module/extensions/datepublisher.py:79 +#: module/extensions/datepublisher.py:80 msgid "visible from - to" -msgstr "видима с - по" +msgstr "" -#: module/extensions/datepublisher.py:89 +#: module/extensions/datepublisher.py:90 msgid "Date-based publishing" -msgstr "Публикация основанная на дате" +msgstr "" #: module/extensions/featured.py:9 msgid "featured" -msgstr "создан" +msgstr "" #: module/extensions/featured.py:14 msgid "Featured" -msgstr "создан" +msgstr "" #: module/extensions/seo.py:9 msgid "meta keywords" -msgstr "ключевые слова" +msgstr "" #: module/extensions/seo.py:10 msgid "This will be prepended to the default keyword list." -msgstr "Будет добавлено к основному списку ключевых слов" +msgstr "" #: module/extensions/seo.py:11 msgid "meta description" -msgstr "описание" +msgstr "" #: module/extensions/seo.py:12 msgid "This will be prepended to the default description." -msgstr "Будет добавлено к основному описанию" +msgstr "" #: module/extensions/seo.py:18 msgid "Search engine optimization" -msgstr "Оптимизация для поисковых систем" +msgstr "" -#: module/extensions/translations.py:175 +#: module/extensions/translations.py:192 msgid "Edit translation" msgstr "Изменить перевод" -#: module/extensions/translations.py:178 +#: module/extensions/translations.py:195 msgid "Create translation" msgstr "Создать перевод" -#: module/extensions/translations.py:183 +#: module/extensions/translations.py:200 msgid "translations" msgstr "переводы" -#: module/medialibrary/models.py:58 +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "Предпросмотр" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "размер файла" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "создан" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "тип файла" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "родитель" -#: module/medialibrary/models.py:60 module/page/models.py:221 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "путь в URL" -#: module/medialibrary/models.py:64 +#: module/medialibrary/models.py:49 msgid "category" msgstr "категория" -#: module/medialibrary/models.py:65 module/medialibrary/models.py:111 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "категории" -#: module/medialibrary/models.py:106 module/medialibrary/models.py:195 -msgid "file type" -msgstr "тип файла" - -#: module/medialibrary/models.py:107 module/medialibrary/models.py:133 -msgid "created" -msgstr "создан" - -#: module/medialibrary/models.py:108 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "" -#: module/medialibrary/models.py:109 module/medialibrary/models.py:128 -msgid "file size" -msgstr "размер файла" - -#: module/medialibrary/models.py:216 -msgid "file info" -msgstr "файл" - -#: module/medialibrary/models.py:293 +#: module/medialibrary/models.py:202 msgid "Image" msgstr "Изображение" -#: module/medialibrary/models.py:294 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "Видео" -#: module/medialibrary/models.py:295 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "Аудио" -#: module/medialibrary/models.py:296 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "Документ PDF" -#: module/medialibrary/models.py:297 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "" -#: module/medialibrary/models.py:298 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "Текст" -#: module/medialibrary/models.py:299 +#: module/medialibrary/models.py:208 msgid "Rich Text" -msgstr "Текст" +msgstr "" -#: module/medialibrary/models.py:300 +#: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "Zip-архив" +msgstr "" -#: module/medialibrary/models.py:301 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" -msgstr "документ Microsoft Word" +msgstr "" -#: module/medialibrary/models.py:302 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" -msgstr "документ Microsoft Excel" +msgstr "" -#: module/medialibrary/models.py:303 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" -msgstr "PowerPoint документ" +msgstr "" -#: module/medialibrary/models.py:304 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "Двоичный" -#: module/medialibrary/models.py:320 -msgid "caption" -msgstr "подпись" - -#: module/medialibrary/models.py:321 +#: module/medialibrary/models.py:236 msgid "description" msgstr "описание" -#: module/medialibrary/models.py:324 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "" -#: module/medialibrary/models.py:325 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "" -#: module/medialibrary/models.py:347 -#: templates/admin/feincms/page/page/item_editor.html:14 -msgid "Preview" -msgstr "Предпросмотр" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "Этот URL уже занят активной страницей." -#: module/medialibrary/models.py:367 -#, python-format -msgid "Successfully added %(count)d media file to %(category)s." -msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "Добавлено %(count)d документов в %(category)s." -msgstr[1] "Добавлен %(count)d документ в %(category)s." -msgstr[2] "Добавлено %(count)d документов в %(category)s." +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "Этот URL уже занят другой активной страницей." -#: module/medialibrary/models.py:385 -msgid "Add selected media files to category" -msgstr "Добавить выбранные файлы в категорию" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "Другие параметры" -#: module/medialibrary/models.py:394 -#, python-format -msgid "ZIP file exported as %s" -msgstr "ZIP-архив экспортирован как %s" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "в навигации" -#: module/medialibrary/models.py:396 -#, python-format -msgid "ZIP file export failed: %s" -msgstr "Ошибка экспорта в ZIP-архив: %s" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "" -#: module/medialibrary/models.py:400 -msgid "Export selected media files as zip file" -msgstr "Упаковать выбранные файлы в ZIP-архив" +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "" -#: module/medialibrary/models.py:423 -#, python-format +#: module/page/modeladmins.py:130 msgid "" -"Cannot overwrite with different file type (attempt to overwrite a " -"%(old_ext)s with a %(new_ext)s)" +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -"Невозможно изменить тип файла (Попытка сохранить %(old_ext)s в %(new_ext)s))" -#: module/medialibrary/models.py:466 -#, python-format -msgid "%d files imported" -msgstr "%d файлов импортировано" +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" +msgstr "" -#: module/medialibrary/models.py:468 -#, python-format -msgid "ZIP import failed: %s" -msgstr "Загрузка ZIP-архива не удалась: %s" +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "" -#: module/medialibrary/models.py:470 -msgid "No input file given" -msgstr "не заданы файлы" +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "расширения" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "" -#: module/page/models.py:217 +#: module/page/models.py:138 msgid "active" msgstr "активная" -#: module/page/models.py:224 module/page/models.py:729 -msgid "in navigation" -msgstr "в навигации" - -#: module/page/models.py:225 +#: module/page/models.py:146 msgid "override URL" -msgstr "перекрыть адрес" +msgstr "" -#: module/page/models.py:226 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -"Перекрыть адрес. Убедитесь что адрес начинается и заканчивается слэшем (/) " -"для локальных адресов. Это отностися и к навигации и к подстраницам." -#: module/page/models.py:227 +#: module/page/models.py:148 msgid "redirect to" msgstr "редирект на" -#: module/page/models.py:228 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." -msgstr "Адрес для автоматического перенаправления" +msgstr "" -#: module/page/models.py:229 +#: module/page/models.py:150 msgid "Cached URL" msgstr "" -#: module/page/models.py:240 +#: module/page/models.py:161 msgid "page" msgstr "страница" -#: module/page/models.py:241 +#: module/page/models.py:162 msgid "pages" msgstr "страницы" -#: module/page/models.py:258 module/page/models.py:809 -msgid "is active" -msgstr "активная" - -#: module/page/models.py:639 -msgid "This URL is already taken by an active page." -msgstr "Этот URL уже занят активной страницей." - -#: module/page/models.py:657 -msgid "This URL is already taken by another active page." -msgstr "Этот URL уже занят другой активной страницей." - -#: module/page/models.py:681 -msgid "Other options" -msgstr "Другие параметры" - -#: module/page/models.py:740 -msgid "Add child page" -msgstr "Добавить дочернюю страницу" - -#: module/page/models.py:742 templates/admin/feincms/content_inline.html:9 -msgid "View on site" -msgstr "Посмотреть на сайте" - -#: module/page/models.py:772 -msgid "" -"The content from the original translation has been copied to the newly " -"created page." -msgstr "Содержимое с оригинальной страницы скопировано в новую." - -#: module/page/models.py:786 -msgid "You don't have the necessary permissions to edit this object" -msgstr "У вас нет прад для редактирования объекта" - -#: module/page/models.py:801 -msgid "inherited" -msgstr "унаследовано" - -#: module/page/models.py:805 -msgid "extensions" -msgstr "расширения" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" -msgstr "выдержка" +msgstr "" #: module/page/extensions/excerpt.py:10 msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Добавить краткую выдержку описывающую содержимое страницы." +msgstr "" #: module/page/extensions/excerpt.py:12 msgid "Excerpt" -msgstr "Выдержка" +msgstr "" -#: module/page/extensions/navigation.py:74 -#: module/page/extensions/navigation.py:94 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" -msgstr "расширение навигации" +msgstr "" -#: module/page/extensions/navigation.py:96 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "Выберите модуль, расширяющий навигацию по дочерним страницам" +msgstr "" -#: module/page/extensions/navigation.py:109 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" -msgstr "Расширение навигации" +msgstr "" #: module/page/extensions/relatedpages.py:13 msgid "Select pages that should be listed as related content." -msgstr "Выбертие страницу, которая будет показана в списке связанных страниц" +msgstr "" #: module/page/extensions/relatedpages.py:20 msgid "Related pages" -msgstr "Связанные страницы" +msgstr "" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "Сайт" +msgstr "" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" -msgstr "Страница-ссылка" +msgstr "" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "Все содержимое будет взято с этой страницы." - -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "Страница-ссылка" +msgstr "" #: module/page/extensions/titles.py:13 msgid "content title" -msgstr "Заголовок содержимого" +msgstr "" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "ПЕрвая строка - основной заголовок, остальное - подзаголовоки" +msgstr "" #: module/page/extensions/titles.py:15 msgid "page title" @@ -763,12 +779,12 @@ msgstr "Элемент успешно удален." #: templates/admin/feincms/_messages_js.html:5 msgid "Cannot delete item" -msgstr "невозможно удалить элемент" +msgstr "Не выходит удалить элемент" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." msgstr "" -"Невозможно удалить элемент, т.к. он является родителем как минимум для " +"Не выходит удалить элемент, т.к. он является родителем как минимум для " "одного другого элемента." #: templates/admin/feincms/_messages_js.html:7 @@ -783,11 +799,8 @@ msgstr "Точно сменить шаблон? <br/> Все изменения #, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" -"Вы действительно хотите изменить шаблон? <br /> Все сохраненные изменение и " -"содержимое региона <strong>%(source_regions)s</strong> будут перенесены в " -"<strong>%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -818,8 +831,6 @@ msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." msgstr "" -"Содержимое родительского элемента автоматически наследуется. Для перекрытия " -"этого поведение нужно добавить содержимое." #: templates/admin/feincms/content_editor.html:23 msgid "Add new item" @@ -828,72 +839,72 @@ msgstr "Добавить элемент" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "Добавить еще %(verbose_name)s" +msgstr "" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" -msgstr "Удалить" +msgstr "" #: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "Сохранить" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "Закончить редактирование" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "редактировать" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "новый" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "вверх" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "вниз" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "удалить" -#: templates/admin/feincms/recover_form.html:7 -#: templates/admin/feincms/revision_form.html:10 -#: templates/admin/feincms/page/page/item_editor.html:22 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" msgstr "Начало" -#: templates/admin/feincms/recover_form.html:10 +#: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "Восстановить %(verbose_name)s" +msgstr "" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "Для восстановления этой версии нажмите сохранить." +msgstr "" -#: templates/admin/feincms/revision_form.html:14 +#: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "История" +msgstr "" -#: templates/admin/feincms/revision_form.html:15 +#: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "Отменить %(verbose_name)s" +msgstr "" -#: templates/admin/feincms/revision_form.html:28 +#: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "Для возврата к этой версии нажмите сохранить." +msgstr "" #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" -msgstr "Ярлыки" +msgstr "" #: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" @@ -905,46 +916,46 @@ msgstr "Развернуть дерево" #: templates/admin/feincms/tree_editor.html:38 msgid "Filter" -msgstr "Фильтр" +msgstr "" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "Редактировать на сайте" -#: templates/admin/feincms/page/page/item_editor.html:26 +#: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "Добавить" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "Добавить медиа файлы в категорию" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "Выберите категорию:" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "Следующие файлы будут добавлены в выбранную категорию:" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "Добавить в категорию" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "Отменить" +msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "Загрузить несколько файлов в ZIP-архиве:" -#: templates/admin/medialibrary/mediafile/change_list.html:22 +#: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "Перезаписать" +msgstr "" -#: templates/admin/medialibrary/mediafile/change_list.html:25 +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "Отправить" @@ -981,12 +992,3 @@ msgstr "Отправить" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Спасибо!" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Вы можете отредактировать скопированную страницу ниже." - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Заменить страницу %(to_replace)s" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Создать скрытую копию этой страницы" diff --git a/feincms/locale/tr/LC_MESSAGES/django.po b/feincms/locale/tr/LC_MESSAGES/django.po new file mode 100644 index 000000000..7134c780b --- /dev/null +++ b/feincms/locale/tr/LC_MESSAGES/django.po @@ -0,0 +1,979 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: FeinCMS\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"Language-Team: Turkish (http://www.transifex.com/projects/p/feincms/language/" +"tr/)\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#: models.py:420 content/template/models.py:59 +msgid "template" +msgstr "" + +#: models.py:551 +msgid "ordering" +msgstr "" + +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 +msgid "language" +msgstr "" + +#: admin/filterspecs.py:35 admin/filterspecs.py:70 +msgid "All" +msgstr "" + +#: admin/filterspecs.py:46 module/page/models.py:143 +msgid "Parent" +msgstr "" + +#: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 +msgid "Category" +msgstr "" + +#: admin/item_editor.py:157 +#, python-format +msgid "Change %s" +msgstr "" + +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 +msgid "title" +msgstr "" + +#: admin/tree_editor.py:404 +#, python-format +msgid "%s has been moved to a new position." +msgstr "" + +#: admin/tree_editor.py:408 +msgid "Did not understand moving instruction." +msgstr "" + +#: admin/tree_editor.py:417 +msgid "actions" +msgstr "" + +#: admin/tree_editor.py:429 +#, python-format +msgid "Successfully deleted %s items." +msgstr "" + +#: admin/tree_editor.py:437 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: content/application/models.py:272 +msgid "application content" +msgstr "" + +#: content/application/models.py:273 +msgid "application contents" +msgstr "" + +#: content/application/models.py:298 +msgid "application" +msgstr "" + +#: content/comments/models.py:24 +msgid "enabled" +msgstr "" + +#: content/comments/models.py:24 +msgid "New comments may be added" +msgstr "" + +#: content/comments/models.py:28 content/comments/models.py:29 +msgid "comments" +msgstr "" + +#: content/comments/models.py:49 +msgid "public" +msgstr "" + +#: content/comments/models.py:49 +msgid "not public" +msgstr "" + +#: content/contactform/models.py:18 +msgid "name" +msgstr "" + +#: content/contactform/models.py:19 +msgid "email" +msgstr "" + +#: content/contactform/models.py:20 +msgid "subject" +msgstr "" + +#: content/contactform/models.py:23 content/raw/models.py:14 +msgid "content" +msgstr "" + +#: content/contactform/models.py:34 +msgid "contact form" +msgstr "" + +#: content/contactform/models.py:35 +msgid "contact forms" +msgstr "" + +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 +msgid "file" +msgstr "" + +#: content/file/models.py:26 +msgid "files" +msgstr "" + +#: content/image/models.py:43 content/image/models.py:52 +msgid "image" +msgstr "" + +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "" + +#: content/image/models.py:53 +msgid "images" +msgstr "" + +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 +msgid "position" +msgstr "" + +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 +msgid "(no caption)" +msgstr "" + +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 +msgid "media file" +msgstr "" + +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 +msgid "media files" +msgstr "" + +#: content/medialibrary/models.py:139 +msgid "block" +msgstr "" + +#: content/medialibrary/models.py:140 +msgid "left" +msgstr "" + +#: content/medialibrary/models.py:141 +msgid "right" +msgstr "" + +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 +msgid "type" +msgstr "" + +#: content/raw/models.py:18 +msgid "raw content" +msgstr "" + +#: content/raw/models.py:19 +msgid "raw contents" +msgstr "" + +#: content/richtext/models.py:22 +msgid "HTML Tidy" +msgstr "" + +#: content/richtext/models.py:23 +msgid "Ignore the HTML validation warnings" +msgstr "" + +#: content/richtext/models.py:47 +#, python-format +msgid "" +"HTML validation produced %(count)d warnings. Please review the updated " +"content below before continuing: %(messages)s" +msgstr "" + +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "" + +#: content/richtext/models.py:85 +msgid "rich text" +msgstr "" + +#: content/richtext/models.py:86 +msgid "rich texts" +msgstr "" + +#: content/rss/models.py:21 +msgid "" +"The rss field is updated several times a day. A change in the title will " +"only be visible on the home page after the next feed update." +msgstr "" + +#: content/rss/models.py:22 +msgid "link" +msgstr "" + +#: content/rss/models.py:23 +msgid "pre-rendered content" +msgstr "" + +#: content/rss/models.py:24 +msgid "last updated" +msgstr "" + +#: content/rss/models.py:25 +msgid "max. items" +msgstr "" + +#: content/rss/models.py:29 +msgid "RSS feed" +msgstr "" + +#: content/rss/models.py:30 +msgid "RSS feeds" +msgstr "" + +#: content/section/models.py:41 +msgid "section" +msgstr "" + +#: content/section/models.py:42 +msgid "sections" +msgstr "" + +#: content/table/models.py:66 +msgid "plain" +msgstr "" + +#: content/table/models.py:67 +msgid "title row" +msgstr "" + +#: content/table/models.py:69 +msgid "title row and column" +msgstr "" + +#: content/table/models.py:75 +msgid "table" +msgstr "" + +#: content/table/models.py:76 +msgid "tables" +msgstr "" + +#: content/table/models.py:90 +msgid "data" +msgstr "" + +#: content/template/models.py:51 +msgid "template content" +msgstr "" + +#: content/template/models.py:52 +msgid "template contents" +msgstr "" + +#: content/video/models.py:25 +msgid "video link" +msgstr "" + +#: content/video/models.py:26 +msgid "" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" + +#: content/video/models.py:30 +msgid "video" +msgstr "" + +#: content/video/models.py:31 +msgid "videos" +msgstr "" + +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 +msgid "published" +msgstr "" + +#: module/blog/models.py:30 +msgid "This is used for the generated navigation too." +msgstr "" + +#: module/blog/models.py:33 +msgid "published on" +msgstr "" + +#: module/blog/models.py:34 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" + +#: module/blog/models.py:39 +msgid "entry" +msgstr "" + +#: module/blog/models.py:40 +msgid "entries" +msgstr "" + +#: module/blog/extensions/tags.py:12 +msgid "tags" +msgstr "" + +#: module/blog/extensions/translations.py:20 +#: module/extensions/translations.py:122 +msgid "translation of" +msgstr "" + +#: module/blog/extensions/translations.py:23 +#: module/extensions/translations.py:125 +msgid "Leave this empty for entries in the primary language." +msgstr "" + +#: module/blog/extensions/translations.py:44 +#: templates/admin/feincms/item_editor.html:43 +msgid "available translations" +msgstr "" + +#: module/extensions/changedate.py:32 +msgid "creation date" +msgstr "" + +#: module/extensions/changedate.py:33 +msgid "modification date" +msgstr "" + +#: module/extensions/ct_tracker.py:136 +msgid "content types" +msgstr "" + +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "" + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "" + +#: module/extensions/featured.py:9 +msgid "featured" +msgstr "" + +#: module/extensions/featured.py:14 +msgid "Featured" +msgstr "" + +#: module/extensions/seo.py:9 +msgid "meta keywords" +msgstr "" + +#: module/extensions/seo.py:10 +msgid "This will be prepended to the default keyword list." +msgstr "" + +#: module/extensions/seo.py:11 +msgid "meta description" +msgstr "" + +#: module/extensions/seo.py:12 +msgid "This will be prepended to the default description." +msgstr "" + +#: module/extensions/seo.py:18 +msgid "Search engine optimization" +msgstr "" + +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "" + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "" + +#: module/medialibrary/models.py:43 +msgid "parent" +msgstr "" + +#: module/medialibrary/models.py:45 module/page/models.py:142 +msgid "slug" +msgstr "" + +#: module/medialibrary/models.py:49 +msgid "category" +msgstr "" + +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +msgid "categories" +msgstr "" + +#: module/medialibrary/models.py:87 +msgid "copyright" +msgstr "" + +#: module/medialibrary/models.py:202 +msgid "Image" +msgstr "" + +#: module/medialibrary/models.py:203 +msgid "Video" +msgstr "" + +#: module/medialibrary/models.py:204 +msgid "Audio" +msgstr "" + +#: module/medialibrary/models.py:205 +msgid "PDF document" +msgstr "" + +#: module/medialibrary/models.py:206 +msgid "Flash" +msgstr "" + +#: module/medialibrary/models.py:207 +msgid "Text" +msgstr "" + +#: module/medialibrary/models.py:208 +msgid "Rich Text" +msgstr "" + +#: module/medialibrary/models.py:209 +msgid "Zip archive" +msgstr "" + +#: module/medialibrary/models.py:210 +msgid "Microsoft Word" +msgstr "" + +#: module/medialibrary/models.py:211 +msgid "Microsoft Excel" +msgstr "" + +#: module/medialibrary/models.py:212 +msgid "Microsoft PowerPoint" +msgstr "" + +#: module/medialibrary/models.py:213 +msgid "Binary" +msgstr "" + +#: module/medialibrary/models.py:236 +msgid "description" +msgstr "" + +#: module/medialibrary/models.py:239 +msgid "media file translation" +msgstr "" + +#: module/medialibrary/models.py:240 +msgid "media file translations" +msgstr "" + +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "" + +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "" + +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "" + +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "" + +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "" + +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." +msgstr "" + +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" +msgstr "" + +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" +msgstr "" + +#: module/page/models.py:138 +msgid "active" +msgstr "" + +#: module/page/models.py:146 +msgid "override URL" +msgstr "" + +#: module/page/models.py:147 +msgid "" +"Override the target URL. Be sure to include slashes at the beginning and at " +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" + +#: module/page/models.py:148 +msgid "redirect to" +msgstr "" + +#: module/page/models.py:149 +msgid "Target URL for automatic redirects." +msgstr "" + +#: module/page/models.py:150 +msgid "Cached URL" +msgstr "" + +#: module/page/models.py:161 +msgid "page" +msgstr "" + +#: module/page/models.py:162 +msgid "pages" +msgstr "" + +#: module/page/extensions/excerpt.py:9 +msgid "excerpt" +msgstr "" + +#: module/page/extensions/excerpt.py:10 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" + +#: module/page/extensions/excerpt.py:12 +msgid "Excerpt" +msgstr "" + +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 +msgid "navigation extension" +msgstr "" + +#: module/page/extensions/navigation.py:102 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" + +#: module/page/extensions/navigation.py:115 +msgid "Navigation extension" +msgstr "" + +#: module/page/extensions/relatedpages.py:13 +msgid "Select pages that should be listed as related content." +msgstr "" + +#: module/page/extensions/relatedpages.py:20 +msgid "Related pages" +msgstr "" + +#: module/page/extensions/sites.py:16 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:15 +msgid "symlinked page" +msgstr "" + +#: module/page/extensions/symlinks.py:16 +msgid "All content is inherited from this page if given." +msgstr "" + +#: module/page/extensions/titles.py:13 +msgid "content title" +msgstr "" + +#: module/page/extensions/titles.py:14 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" + +#: module/page/extensions/titles.py:15 +msgid "page title" +msgstr "" + +#: module/page/extensions/titles.py:16 +msgid "Page title for browser window. Same as title by default." +msgstr "" + +#: module/page/extensions/titles.py:43 +msgid "Titles" +msgstr "" + +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" + +#: templates/admin/content/mediafile/init.html:9 +msgid "Search" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:4 +msgid "Really delete item?" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:4 +msgid "Confirm to delete item" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:5 +msgid "Item deleted successfully." +msgstr "" + +#: templates/admin/feincms/_messages_js.html:5 +msgid "Cannot delete item" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:6 +msgid "Cannot delete item, because it is parent of at least one other item." +msgstr "" + +#: templates/admin/feincms/_messages_js.html:7 +msgid "Change template" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:8 +msgid "Really change template? <br />All changes are saved." +msgstr "" + +#: templates/admin/feincms/_messages_js.html:9 +#, python-format +msgid "" +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +msgstr "" + +#: templates/admin/feincms/_messages_js.html:12 +msgid "Hide" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:13 +msgid "Show" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:14 +msgid "After" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:15 +msgid "Before" +msgstr "" + +#: templates/admin/feincms/_messages_js.html:16 +msgid "Insert new:" +msgstr "" + +#: templates/admin/feincms/content_editor.html:11 +msgid "Region empty" +msgstr "" + +#: templates/admin/feincms/content_editor.html:15 +msgid "" +"Content from the parent site is automatically inherited. To override this " +"behaviour, add some content." +msgstr "" + +#: templates/admin/feincms/content_editor.html:23 +msgid "Add new item" +msgstr "" + +#: templates/admin/feincms/content_inline.html:91 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/content_inline.html:94 +msgid "Remove" +msgstr "" + +#: templates/admin/feincms/fe_editor.html:40 +msgid "Save" +msgstr "" + +#: templates/admin/feincms/fe_tools.html:28 +msgid "Stop Editing" +msgstr "" + +#: templates/admin/feincms/fe_tools.html:33 +msgid "edit" +msgstr "" + +#: templates/admin/feincms/fe_tools.html:35 +msgid "new" +msgstr "" + +#: templates/admin/feincms/fe_tools.html:36 +msgid "up" +msgstr "" + +#: templates/admin/feincms/fe_tools.html:37 +msgid "down" +msgstr "" + +#: templates/admin/feincms/fe_tools.html:38 +msgid "remove" +msgstr "" + +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 +#: templates/admin/feincms/page/page/tree_editor.html:7 +msgid "Home" +msgstr "" + +#: templates/admin/feincms/recover_form.html:11 +#, python-format +msgid "Recover deleted %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/recover_form.html:17 +msgid "Press the save button below to recover this version of the object." +msgstr "" + +#: templates/admin/feincms/revision_form.html:12 +msgid "History" +msgstr "" + +#: templates/admin/feincms/revision_form.html:13 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/admin/feincms/revision_form.html:24 +msgid "Press the save button below to revert to this version of the object." +msgstr "" + +#: templates/admin/feincms/tree_editor.html:32 +msgid "Shortcuts" +msgstr "" + +#: templates/admin/feincms/tree_editor.html:34 +msgid "Collapse tree" +msgstr "" + +#: templates/admin/feincms/tree_editor.html:35 +msgid "Expand tree" +msgstr "" + +#: templates/admin/feincms/tree_editor.html:38 +msgid "Filter" +msgstr "" + +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "" + +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + +#: templates/admin/medialibrary/add_to_category.html:5 +#: templates/admin/medialibrary/add_to_category.html:9 +msgid "Add media files to category" +msgstr "" + +#: templates/admin/medialibrary/add_to_category.html:11 +msgid "Select category to apply:" +msgstr "" + +#: templates/admin/medialibrary/add_to_category.html:17 +msgid "The following media files will be added to the selected category:" +msgstr "" + +#: templates/admin/medialibrary/add_to_category.html:22 +msgid "Add to category" +msgstr "" + +#: templates/admin/medialibrary/add_to_category.html:23 +msgid "Cancel" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:11 +msgid "Bulk upload a ZIP file:" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 +msgid "Send" +msgstr "" + +#: templates/content/comments/default.html:10 +#, python-format +msgid "%(comment_count)s comments." +msgstr "" + +#: templates/content/comments/default.html:18 +#, python-format +msgid "" +"\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" + +#: templates/content/comments/default.html:28 +msgid "No comments." +msgstr "" + +#: templates/content/comments/default.html:36 +msgid "Post Comment" +msgstr "" + +#: templates/content/contactform/form.html:9 +msgid "Submit" +msgstr "" + +#: templates/content/contactform/thanks.html:3 +msgid "Thanks!" +msgstr "" diff --git a/feincms/locale/zh_CN/LC_MESSAGES/django.po b/feincms/locale/zh_CN/LC_MESSAGES/django.po index dda27d321..6e57bf930 100644 --- a/feincms/locale/zh_CN/LC_MESSAGES/django.po +++ b/feincms/locale/zh_CN/LC_MESSAGES/django.po @@ -1,33 +1,35 @@ -# Simplified Chinese Translation For FeinCMS. -# Copyright (C) 2011 THE FeinCMS'S COPYRIGHT HOLDER -# This file is distributed under the same license as the FeinCMS package. -# Mark Renton <indexofire@gmail.com>, 2011. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # -#, fuzzy +# Translators: +# <chenyuan328@gmail.com>, 2011. +# Mark Renton <indexofire@gmail.com>, 2011. msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-05 06:32+0800\n" -"PO-Revision-Date: 2011-08-05 10:20+0800\n" -"Last-Translator: Mark Renton <indexofire@gmail.com>\n" -"Language-Team: zh_CN <indexofire@gmail.com>\n" -"Language: Simplified Chinese\n" +"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Last-Translator: aaffdd11 <chenyuan328@gmail.com>\n" +"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/feincms/" +"language/zh_CN/)\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0\n" -#: models.py:343 content/template/models.py:39 content/template/models.py:57 +#: models.py:420 content/template/models.py:59 msgid "template" msgstr "模板" -#: models.py:522 +#: models.py:551 msgid "ordering" msgstr "排序" -#: translations.py:171 module/blog/extensions/translations.py:17 -#: module/page/extensions/translations.py:102 +#: translations.py:259 module/blog/extensions/translations.py:17 +#: module/extensions/translations.py:119 msgid "language" msgstr "语言" @@ -35,68 +37,79 @@ msgstr "语言" msgid "All" msgstr "全部" -#: admin/filterspecs.py:46 module/page/models.py:254 +#: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" msgstr "父级" #: admin/filterspecs.py:81 +#: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "分类" -#: admin/item_editor.py:140 +#: admin/item_editor.py:157 #, python-format msgid "Change %s" msgstr "修改 %s" -#: admin/tree_editor.py:219 content/rss/models.py:20 -#: content/section/models.py:32 module/blog/models.py:31 -#: module/medialibrary/models.py:48 module/page/models.py:251 -#: module/page/models.py:327 +#: admin/tree_editor.py:229 content/rss/models.py:20 +#: content/section/models.py:34 module/blog/models.py:29 +#: module/medialibrary/models.py:40 module/page/models.py:141 +#: module/page/models.py:199 msgid "title" msgstr "标题" -#: admin/tree_editor.py:397 +#: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." msgstr "%s 已被移至新的位置" -#: admin/tree_editor.py:401 +#: admin/tree_editor.py:408 msgid "Did not understand moving instruction." msgstr "无法接受的移动指令" -#: admin/tree_editor.py:410 +#: admin/tree_editor.py:417 msgid "actions" msgstr "动作" -#: content/application/models.py:186 +#: admin/tree_editor.py:429 +#, fuzzy, python-format +msgid "Successfully deleted %s items." +msgstr "真的要删除?" + +#: admin/tree_editor.py:437 +#, fuzzy, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Recover deleted %(verbose_name)s" + +#: content/application/models.py:272 msgid "application content" msgstr "应用程序内容" -#: content/application/models.py:187 +#: content/application/models.py:273 msgid "application contents" msgstr "应用程序内容" -#: content/application/models.py:218 +#: content/application/models.py:298 msgid "application" msgstr "应用程序" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "enabled" msgstr "激活" -#: content/comments/models.py:28 +#: content/comments/models.py:24 msgid "New comments may be added" msgstr "新的评论" -#: content/comments/models.py:32 content/comments/models.py:33 +#: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" msgstr "评论" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "public" msgstr "公开" -#: content/comments/models.py:48 +#: content/comments/models.py:49 msgid "not public" msgstr "不公开" @@ -124,54 +137,77 @@ msgstr "联系表单" msgid "contact forms" msgstr "联系表单" -#: content/file/models.py:16 content/file/models.py:20 -#: module/medialibrary/models.py:98 +#: content/file/models.py:20 content/file/models.py:25 +#: module/medialibrary/models.py:84 msgid "file" msgstr "文件" -#: content/file/models.py:21 +#: content/file/models.py:26 msgid "files" msgstr "文件" -#: content/image/models.py:24 content/image/models.py:28 +#: content/image/models.py:43 content/image/models.py:52 msgid "image" msgstr "图片" -#: content/image/models.py:29 +#: content/image/models.py:46 +msgid "alternate text" +msgstr "" + +#: content/image/models.py:47 +msgid "Description of image" +msgstr "" + +#: content/image/models.py:48 module/medialibrary/models.py:235 +msgid "caption" +msgstr "题目" + +#: content/image/models.py:53 msgid "images" msgstr "图片" -#: content/image/models.py:42 content/medialibrary/models.py:100 -#: content/medialibrary/models.py:108 +#: content/image/models.py:79 content/medialibrary/models.py:115 +#: content/medialibrary/models.py:123 msgid "position" msgstr "位置" -#: content/medialibrary/models.py:36 +#: content/image/models.py:87 +msgid "format" +msgstr "" + +#: content/medialibrary/models.py:48 msgid "(no caption)" msgstr "(无标题)" -#: content/medialibrary/models.py:85 content/medialibrary/models.py:96 -#: content/medialibrary/models.py:106 content/section/models.py:48 -#: module/medialibrary/models.py:110 +#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 +#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 +#: content/section/models.py:36 module/medialibrary/fields.py:58 +#: module/medialibrary/models.py:97 msgid "media file" msgstr "多媒体文件" -#: content/medialibrary/models.py:86 module/medialibrary/models.py:111 +#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 +#: module/medialibrary/models.py:98 msgid "media files" msgstr "多媒体文件" -#: content/medialibrary/models.py:126 +#: content/medialibrary/models.py:139 msgid "block" msgstr "区块" -#: content/medialibrary/models.py:127 +#: content/medialibrary/models.py:140 msgid "left" msgstr "左" -#: content/medialibrary/models.py:128 +#: content/medialibrary/models.py:141 msgid "right" msgstr "右" +#: content/medialibrary/v2.py:53 content/section/models.py:52 +#: content/table/models.py:85 +msgid "type" +msgstr "类型" + #: content/raw/models.py:18 msgid "raw content" msgstr "raw content" @@ -180,32 +216,31 @@ msgstr "raw content" msgid "raw contents" msgstr "raw contents" -#: content/richtext/models.py:15 content/richtext/models.py:85 -#: content/section/models.py:33 -msgid "text" -msgstr "纯文本" - -#: content/richtext/models.py:26 +#: content/richtext/models.py:22 msgid "HTML Tidy" -msgstr "HTML" +msgstr "HTML Tidy" -#: content/richtext/models.py:27 +#: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" msgstr "忽略HTML验证错误警告" -#: content/richtext/models.py:51 +#: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "HTML验证产生 %(count)d 个警告。请在继续前查看下面更新的内容:" -" %(messages)s" +msgstr "" +"HTML验证产生 %(count)d 个警告。请在继续前查看下面更新的内容: %(messages)s" -#: content/richtext/models.py:89 +#: content/richtext/models.py:81 content/section/models.py:35 +msgid "text" +msgstr "纯文本" + +#: content/richtext/models.py:85 msgid "rich text" msgstr "富文本" -#: content/richtext/models.py:90 +#: content/richtext/models.py:86 msgid "rich texts" msgstr "富文本" @@ -239,91 +274,91 @@ msgstr "RSS 提要" msgid "RSS feeds" msgstr "RSS 提要" -#: content/section/models.py:37 +#: content/section/models.py:41 msgid "section" msgstr "版块" -#: content/section/models.py:38 +#: content/section/models.py:42 msgid "sections" msgstr "版块" -#: content/section/models.py:53 content/section/models.py:61 -#: content/table/models.py:81 -msgid "type" -msgstr "类型" - -#: content/table/models.py:62 +#: content/table/models.py:66 msgid "plain" msgstr "无格式" -#: content/table/models.py:63 +#: content/table/models.py:67 msgid "title row" msgstr "标题行" -#: content/table/models.py:65 +#: content/table/models.py:69 msgid "title row and column" msgstr "标题行和列" -#: content/table/models.py:71 +#: content/table/models.py:75 msgid "table" msgstr "表格" -#: content/table/models.py:72 +#: content/table/models.py:76 msgid "tables" msgstr "表格" -#: content/table/models.py:86 +#: content/table/models.py:90 msgid "data" msgstr "数据" -#: content/template/models.py:62 +#: content/template/models.py:51 msgid "template content" msgstr "模板内容" -#: content/template/models.py:63 +#: content/template/models.py:52 msgid "template contents" msgstr "模板内容" -#: content/video/models.py:23 +#: content/video/models.py:25 msgid "video link" msgstr "视频链接" -#: content/video/models.py:24 +#: content/video/models.py:26 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" -msgstr "请输入youtube或vimeo视频链接,比如:http://www.youtube.com/watch?" +msgstr "" +"请输入youtube或vimeo视频链接,比如:http://www.youtube.com/watch?" "v=zmj1rpzDRZ0" -#: content/video/models.py:28 +#: content/video/models.py:30 msgid "video" msgstr "视频" -#: content/video/models.py:29 +#: content/video/models.py:31 msgid "videos" msgstr "视频" -#: module/blog/models.py:30 +#: contrib/tagging.py:117 +msgid "Tagging" +msgstr "" + +#: module/blog/models.py:28 msgid "published" msgstr "已发布" -#: module/blog/models.py:32 module/page/models.py:252 +#: module/blog/models.py:30 msgid "This is used for the generated navigation too." msgstr "也被用于产生导航条" -#: module/blog/models.py:35 +#: module/blog/models.py:33 msgid "published on" msgstr "发布于" -#: module/blog/models.py:36 +#: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "一旦你将`发表`复选框以上打勾选中,日志将设置成自动发布。" -#: module/blog/models.py:41 +#: module/blog/models.py:39 msgid "entry" msgstr "条目" -#: module/blog/models.py:42 +#: module/blog/models.py:40 msgid "entries" msgstr "条目" @@ -332,32 +367,52 @@ msgid "tags" msgstr "标签" #: module/blog/extensions/translations.py:20 -#: module/page/extensions/translations.py:105 +#: module/extensions/translations.py:122 msgid "translation of" msgstr "翻译" #: module/blog/extensions/translations.py:23 -#: module/page/extensions/translations.py:108 +#: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." msgstr "在主要语言项中对这些条目留空。" #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:69 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "已有翻译" -#: module/extensions/changedate.py:38 +#: module/extensions/changedate.py:32 msgid "creation date" msgstr "创建日期" -#: module/extensions/changedate.py:39 +#: module/extensions/changedate.py:33 msgid "modification date" msgstr "修改日期" -#: module/extensions/ct_tracker.py:117 +#: module/extensions/ct_tracker.py:136 msgid "content types" msgstr "内容类型" +#: module/extensions/datepublisher.py:49 +msgid "publication date" +msgstr "发布起始日期" + +#: module/extensions/datepublisher.py:51 +msgid "publication end date" +msgstr "发布结束日期" + +#: module/extensions/datepublisher.py:53 +msgid "Leave empty if the entry should stay active forever." +msgstr "如果条目要永久显示,请留空" + +#: module/extensions/datepublisher.py:80 +msgid "visible from - to" +msgstr "可查看日期" + +#: module/extensions/datepublisher.py:90 +msgid "Date-based publishing" +msgstr "发布基于日期控制" + #: module/extensions/featured.py:9 msgid "featured" msgstr "特性" @@ -386,225 +441,252 @@ msgstr "这将作为默认的描述被添加" msgid "Search engine optimization" msgstr "搜索引擎优化" -#: module/medialibrary/models.py:51 +#: module/extensions/translations.py:192 +msgid "Edit translation" +msgstr "编辑翻译" + +#: module/extensions/translations.py:195 +msgid "Create translation" +msgstr "创建翻译" + +#: module/extensions/translations.py:200 +msgid "translations" +msgstr "翻译" + +#: module/medialibrary/forms.py:26 +msgid "This would create a loop in the hierarchy" +msgstr "" + +#: module/medialibrary/forms.py:64 +#, python-format +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" +msgstr "" + +#: module/medialibrary/modeladmins.py:57 +#, python-format +msgid "Successfully added %(count)d media file to %(category)s." +msgid_plural "Successfully added %(count)d media files to %(category)s." +msgstr[0] "Successfully added %(count)d media files to %(category)s." + +#: module/medialibrary/modeladmins.py:75 +msgid "Add selected media files to category" +msgstr "所选的媒体文件添加到类" + +#: module/medialibrary/modeladmins.py:84 +#, python-format +msgid "ZIP file exported as %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:86 +#, python-format +msgid "ZIP file export failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:91 +msgid "Export selected media files as zip file" +msgstr "" + +#: module/medialibrary/modeladmins.py:134 +#: templates/admin/feincms/page/page/item_editor.html:15 +msgid "Preview" +msgstr "预览" + +#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +msgid "file size" +msgstr "文件大小" + +#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +msgid "created" +msgstr "创建" + +#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +msgid "file type" +msgstr "文件类型" + +#: module/medialibrary/modeladmins.py:184 +msgid "file info" +msgstr "文件信息" + +#: module/medialibrary/modeladmins.py:196 +#, python-format +msgid "%d files imported" +msgstr "导入 %d 个文件" + +#: module/medialibrary/modeladmins.py:198 +#, python-format +msgid "ZIP import failed: %s" +msgstr "" + +#: module/medialibrary/modeladmins.py:200 +msgid "No input file given" +msgstr "没有选择文件" + +#: module/medialibrary/models.py:43 msgid "parent" msgstr "父" -#: module/medialibrary/models.py:53 module/page/models.py:253 +#: module/medialibrary/models.py:45 module/page/models.py:142 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:57 +#: module/medialibrary/models.py:49 msgid "category" msgstr "类别" -#: module/medialibrary/models.py:58 module/medialibrary/models.py:104 +#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" msgstr "类别" -#: module/medialibrary/models.py:99 module/medialibrary/models.py:185 -msgid "file type" -msgstr "文件类型" - -#: module/medialibrary/models.py:100 module/medialibrary/models.py:125 -msgid "created" -msgstr "创建" - -#: module/medialibrary/models.py:101 +#: module/medialibrary/models.py:87 msgid "copyright" msgstr "版权" -#: module/medialibrary/models.py:102 module/medialibrary/models.py:120 -msgid "file size" -msgstr "文件大小" - #: module/medialibrary/models.py:202 -msgid "file info" -msgstr "文件信息" - -#: module/medialibrary/models.py:282 msgid "Image" msgstr "图片" -#: module/medialibrary/models.py:283 +#: module/medialibrary/models.py:203 msgid "Video" msgstr "视频" -#: module/medialibrary/models.py:284 +#: module/medialibrary/models.py:204 msgid "Audio" msgstr "音频" -#: module/medialibrary/models.py:285 +#: module/medialibrary/models.py:205 msgid "PDF document" msgstr "PDF文档" -#: module/medialibrary/models.py:286 +#: module/medialibrary/models.py:206 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:287 +#: module/medialibrary/models.py:207 msgid "Text" msgstr "纯文本" -#: module/medialibrary/models.py:288 +#: module/medialibrary/models.py:208 msgid "Rich Text" msgstr "富文本" -#: module/medialibrary/models.py:289 +#: module/medialibrary/models.py:209 msgid "Zip archive" msgstr "zip压缩包" -#: module/medialibrary/models.py:290 +#: module/medialibrary/models.py:210 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:291 +#: module/medialibrary/models.py:211 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:292 +#: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:293 +#: module/medialibrary/models.py:213 msgid "Binary" msgstr "二进制文件" -#: module/medialibrary/models.py:309 -msgid "caption" -msgstr "题目" - -#: module/medialibrary/models.py:310 +#: module/medialibrary/models.py:236 msgid "description" msgstr "描述" -#: module/medialibrary/models.py:313 +#: module/medialibrary/models.py:239 msgid "media file translation" msgstr "媒体文件翻译" -#: module/medialibrary/models.py:314 +#: module/medialibrary/models.py:240 msgid "media file translations" msgstr "媒体文件翻译" -#: module/medialibrary/models.py:341 -msgid "Preview" -msgstr "预览" +#: module/page/forms.py:118 +msgid "This URL is already taken by an active page." +msgstr "此URL已被其他页面使用" -#: module/medialibrary/models.py:390 -msgid "Could not access storage" -msgstr "无法访问储存" +#: module/page/forms.py:136 +msgid "This URL is already taken by another active page." +msgstr "此URL已被另一个页面使用" -#: module/medialibrary/models.py:411 -#, python-format -msgid "%d files imported" -msgstr "导入 %d 个文件" +#: module/page/modeladmins.py:41 +msgid "Other options" +msgstr "其他选项" -#: module/medialibrary/models.py:413 -#, python-format -msgid "ZIP file invalid: %s" -msgstr "zip文件无效: %s" +#: module/page/modeladmins.py:89 module/page/models.py:145 +msgid "in navigation" +msgstr "导航中" -#: module/medialibrary/models.py:419 -msgid "No input file given" -msgstr "没有选择文件" +#: module/page/modeladmins.py:100 +msgid "Add child page" +msgstr "增加子页面" -#: module/page/models.py:248 -msgid "active" +#: module/page/modeladmins.py:102 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" +msgstr "站内查看" + +#: module/page/modeladmins.py:130 +msgid "" +"The content from the original translation has been copied to the newly " +"created page." +msgstr "" + +#: module/page/modeladmins.py:144 +msgid "You don't have the necessary permissions to edit this object" +msgstr "你无权编辑该对象" + +#: module/page/modeladmins.py:159 +msgid "inherited" +msgstr "继承" + +#: module/page/modeladmins.py:163 +msgid "extensions" +msgstr "扩展" + +#: module/page/modeladmins.py:167 module/page/models.py:179 +msgid "is active" msgstr "激活" -#: module/page/models.py:256 module/page/models.py:795 -msgid "in navigation" -msgstr "导航中" +#: module/page/models.py:138 +msgid "active" +msgstr "激活" -#: module/page/models.py:257 +#: module/page/models.py:146 msgid "override URL" msgstr "URL覆盖" -#: module/page/models.py:258 +#: module/page/models.py:147 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -"覆盖目标URL,如果它是一个本地的URL,一定要包括在开始和结束时的斜线。这会" -"影响导航和子页面的URL" +"覆盖目标URL,如果它是一个本地的URL,一定要包括在开始和结束时的斜线。这会影响" +"导航和子页面的URL" -#: module/page/models.py:259 +#: module/page/models.py:148 msgid "redirect to" msgstr "转向" -#: module/page/models.py:260 +#: module/page/models.py:149 msgid "Target URL for automatic redirects." msgstr "转向目标URL" -#: module/page/models.py:261 +#: module/page/models.py:150 msgid "Cached URL" msgstr "URL缓存" -#: module/page/models.py:272 +#: module/page/models.py:161 msgid "page" msgstr "页面" -#: module/page/models.py:273 +#: module/page/models.py:162 msgid "pages" msgstr "页面" -#: module/page/models.py:290 module/page/models.py:886 -msgid "is active" -msgstr "激活" - -#: module/page/models.py:715 -msgid "This URL is already taken by an active page." -msgstr "此URL已被其他页面使用" - -#: module/page/models.py:733 -msgid "This URL is already taken by another active page." -msgstr "此URL已被另一个页面使用" - -#: module/page/models.py:758 -msgid "Other options" -msgstr "其他选项" - -#: module/page/models.py:802 templates/admin/feincms/item_editor.html:54 -msgid "Add child page" -msgstr "增加子页面" - -#: module/page/models.py:804 templates/admin/feincms/content_inline.html:9 -msgid "View on site" -msgstr "站内查看" - -#: module/page/models.py:863 -msgid "You don't have the necessary permissions to edit this object" -msgstr "你无权编辑该对象" - -#: module/page/models.py:878 -msgid "inherited" -msgstr "继承" - -#: module/page/models.py:882 -msgid "extensions" -msgstr "扩展" - -#: module/page/extensions/datepublisher.py:48 -msgid "publication date" -msgstr "发布起始日期" - -#: module/page/extensions/datepublisher.py:50 -msgid "publication end date" -msgstr "发布结束日期" - -#: module/page/extensions/datepublisher.py:52 -msgid "Leave empty if the entry should stay active forever." -msgstr "如果条目要永久显示,请留空" - -#: module/page/extensions/datepublisher.py:78 -msgid "visible from - to" -msgstr "可查看日期" - -#: module/page/extensions/datepublisher.py:88 -msgid "Date-based publishing" -msgstr "发布基于日期控制" - #: module/page/extensions/excerpt.py:9 msgid "excerpt" msgstr "摘抄" @@ -617,19 +699,18 @@ msgstr "添加一条简要形容页面内容" msgid "Excerpt" msgstr "摘抄" -#: module/page/extensions/navigation.py:77 -#: module/page/extensions/navigation.py:97 +#: module/page/extensions/navigation.py:80 +#: module/page/extensions/navigation.py:100 msgid "navigation extension" msgstr "导航扩展" -#: module/page/extensions/navigation.py:99 +#: module/page/extensions/navigation.py:102 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"如果您需要定制的导航,选择提供此页面的子页面模块。" +msgstr "如果您需要定制的导航,选择提供此页面的子页面模块。" -#: module/page/extensions/navigation.py:112 +#: module/page/extensions/navigation.py:115 msgid "Navigation extension" msgstr "导航扩展" @@ -641,6 +722,10 @@ msgstr "选择页面作为相关页面在列表中显示" msgid "Related pages" msgstr "相关页面" +#: module/page/extensions/sites.py:16 +msgid "Site" +msgstr "网站" + #: module/page/extensions/symlinks.py:15 msgid "symlinked page" msgstr "链接页面" @@ -649,10 +734,6 @@ msgstr "链接页面" msgid "All content is inherited from this page if given." msgstr "所有内容继承于给出的页面" -#: module/page/extensions/symlinks.py:30 -msgid "Symlinked page" -msgstr "链接页面" - #: module/page/extensions/titles.py:13 msgid "content title" msgstr "内容标题" @@ -673,18 +754,6 @@ msgstr "浏览器窗口显示标题默认为页面标题" msgid "Titles" msgstr "标题" -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "编辑翻译" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "创建翻译" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "翻译" - #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " @@ -723,13 +792,13 @@ msgid "Really change template? <br />All changes are saved." msgstr "真的要修改模板么? <br />全部修改已被保存。" #: templates/admin/feincms/_messages_js.html:9 -#, python-format +#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" -"真的修改模板? <br />所有修改已保存,<strong>%(source_regions)s</strong>的内容" -"已被移到<strong>%(target_region)s</strong>" +"真的修改模板? <br />所有修改已保存,<strong>%(source_regions)s</strong>的内" +"容已被移到<strong>%(target_region)s</strong>" #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -759,8 +828,7 @@ msgstr "空区域" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"父站的内容已自动继承。添加新内容会覆盖。" +msgstr "父站的内容已自动继承。添加新内容会覆盖。" #: templates/admin/feincms/content_editor.html:23 msgid "Add new item" @@ -775,64 +843,117 @@ msgstr "添加另一个 %(verbose_name)s" msgid "Remove" msgstr "移除" -#: templates/admin/feincms/fe_editor.html:46 +#: templates/admin/feincms/fe_editor.html:40 msgid "Save" msgstr "保存" -#: templates/admin/feincms/fe_tools.html:27 +#: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" msgstr "暂停编辑" -#: templates/admin/feincms/fe_tools.html:32 +#: templates/admin/feincms/fe_tools.html:33 msgid "edit" msgstr "编辑" -#: templates/admin/feincms/fe_tools.html:34 +#: templates/admin/feincms/fe_tools.html:35 msgid "new" msgstr "新建" -#: templates/admin/feincms/fe_tools.html:35 +#: templates/admin/feincms/fe_tools.html:36 msgid "up" msgstr "上" -#: templates/admin/feincms/fe_tools.html:36 +#: templates/admin/feincms/fe_tools.html:37 msgid "down" msgstr "下" -#: templates/admin/feincms/fe_tools.html:37 +#: templates/admin/feincms/fe_tools.html:38 msgid "remove" msgstr "移除" -#: templates/admin/feincms/tree_editor.html:37 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:23 +#: templates/admin/feincms/page/page/tree_editor.html:7 +msgid "Home" +msgstr "首页" + +#: templates/admin/feincms/recover_form.html:11 +#, python-format +msgid "Recover deleted %(verbose_name)s" +msgstr "Recover deleted %(verbose_name)s" + +#: templates/admin/feincms/recover_form.html:17 +msgid "Press the save button below to recover this version of the object." +msgstr "按下面的“保存”按钮恢复此对象的版本。" + +#: templates/admin/feincms/revision_form.html:12 +msgid "History" +msgstr "历史" + +#: templates/admin/feincms/revision_form.html:13 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "Revert %(verbose_name)s" + +#: templates/admin/feincms/revision_form.html:24 +msgid "Press the save button below to revert to this version of the object." +msgstr "按下面的“保存”按钮,恢复到这个版本的对象。" + +#: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" msgstr "快捷方式" -#: templates/admin/feincms/tree_editor.html:39 +#: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" msgstr "折叠树型" -#: templates/admin/feincms/tree_editor.html:40 +#: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" msgstr "展开树型" -#: templates/admin/feincms/tree_editor.html:43 +#: templates/admin/feincms/tree_editor.html:38 msgid "Filter" msgstr "过滤器" -#: templates/admin/feincms/page/page/item_editor.html:9 +#: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" msgstr "站内编辑" -#: templates/admin/feincms/page/page/item_editor.html:16 -#: templates/admin/feincms/page/page/tree_editor.html:7 -msgid "Home" -msgstr "首页" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "添加" + +#: templates/admin/medialibrary/add_to_category.html:5 +#: templates/admin/medialibrary/add_to_category.html:9 +msgid "Add media files to category" +msgstr "添加媒体文件到分类" -#: templates/admin/medialibrary/mediafile/change_list.html:12 +#: templates/admin/medialibrary/add_to_category.html:11 +msgid "Select category to apply:" +msgstr "选择申请类别:" + +#: templates/admin/medialibrary/add_to_category.html:17 +msgid "The following media files will be added to the selected category:" +msgstr "以下的媒体文件将被添加到选定的类别:" + +#: templates/admin/medialibrary/add_to_category.html:22 +msgid "Add to category" +msgstr "添加到分类" + +#: templates/admin/medialibrary/add_to_category.html:23 +msgid "Cancel" +msgstr "取消" + +#: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" msgstr "批量上传zip文件" #: templates/admin/medialibrary/mediafile/change_list.html:21 +msgid "Overwrite" +msgstr "" + +#: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" msgstr "发送" @@ -869,3 +990,6 @@ msgstr "提交" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "感谢" + +#~ msgid "Symlinked page" +#~ msgstr "链接页面" From ad8474b7c253d9e615be55d41f141181d415bfa1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 16 Aug 2012 19:03:33 +0200 Subject: [PATCH 0504/1590] Improve the copy-pasteability of the feincms_languagelinks documentation --- docs/templatetags.rst | 2 +- feincms/module/page/templatetags/feincms_page_tags.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/templatetags.rst b/docs/templatetags.rst index 3a50a725e..481b3d015 100644 --- a/docs/templatetags.rst +++ b/docs/templatetags.rst @@ -142,7 +142,7 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: {% load feincms_page_tags %} - {% feincms_languagelinks for entry as links all,excludecurrent %} + {% feincms_languagelinks for feincms_page as links all,excludecurrent %} {% for key, name, link in links %} <a href="{% if link %}{{ link }}{% else %}/{{ key }}/{% endif %}">{% trans name %}</a> {% endfor %} diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 99d03af48..f7ac17a7c 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -212,7 +212,7 @@ class LanguageLinksNode(SimpleAssignmentNodeWithVarAndArgs): Example:: - {% feincms_languagelinks for entry as links all,excludecurrent %} + {% feincms_languagelinks for feincms_page as links all,excludecurrent %} {% for key, name, link in links %} <a href="{% if link %}{{ link }}{% else %}/{{ key }}/{% endif %}">{% trans name %}</a> {% endfor %} From 4f2925f9f2a11c6e1114453768d38e1d043abc4c Mon Sep 17 00:00:00 2001 From: Valtron <valtron2000@gmail.com> Date: Fri, 17 Aug 2012 10:28:38 -0600 Subject: [PATCH 0505/1590] Fixed #335: Missing template folder when installing with pip/easy_install --- setuplib.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setuplib.py b/setuplib.py index 653029534..42f6f4ea3 100644 --- a/setuplib.py +++ b/setuplib.py @@ -49,9 +49,10 @@ def find_packages(package_dir): cur_pack = packages[0] # Assign all data files to the toplevel package if cur_pack not in package_data: package_data[cur_pack] = [] - package_dir = "/".join(cur_pack.split(".")) + "/" + package_dir = os.path.join(*cur_pack.split(".")) + dir_relpath = os.path.relpath(dirpath, package_dir) for f in filenames: - package_data[cur_pack].append(os.path.join(dirpath.replace(package_dir, "", 1), f)) + package_data[cur_pack].append(os.path.join(dir_relpath, f)) return packages, package_data From a9f9ed3dbe135c752c11150481ab24c89c9664eb Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Tue, 21 Aug 2012 13:27:56 +0200 Subject: [PATCH 0506/1590] Add failing test for #339 --- feincms/tests/cms_tests.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/feincms/tests/cms_tests.py b/feincms/tests/cms_tests.py index 39b5514ca..3a1edf683 100644 --- a/feincms/tests/cms_tests.py +++ b/feincms/tests/cms_tests.py @@ -18,6 +18,13 @@ from .tests import ExampleCMSBase, Empty, ExampleCMSBase2 # ------------------------------------------------------------------------ +class SubRawContent(RawContent): + title = models.CharField('title', max_length=100, blank=True) + + class Meta: + abstract = True + + class CMSBaseTest(TestCase): def test_01_simple_content_type_creation(self): self.assertEqual(ExampleCMSBase.content_type_for(FileContent), None) @@ -143,3 +150,15 @@ class Meta: self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) self.assertTrue(hasattr(Attachment, 'anycontents')) + def test_10_content_type_subclasses(self): + """ + See: + https://github.com/feincms/feincms/issues/339 + """ + ExampleCMSBase.create_content_type(SubRawContent) + ExampleCMSBase.create_content_type(RawContent) + + ct = ExampleCMSBase.content_type_for(RawContent) + ct2 = ExampleCMSBase.content_type_for(SubRawContent) + self.assertNotEqual(ct, ct2) + From 3ba660a49a9286a231b5a85fb7a1f0235e2d8fcc Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Tue, 21 Aug 2012 13:28:36 +0200 Subject: [PATCH 0507/1590] Fix #339 Wrong result for content_type_for when using subclass of content model --- feincms/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index ad401c057..e7fbdad4d 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -751,7 +751,8 @@ def content_type_for(cls, model): for type in cls._feincms_content_types: if issubclass(type, model): - return type + if type.__base__ is model: + return type return None @classmethod From 33f7eabe32ed2e7cdd0fe9f1021605d29863b578 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Tue, 21 Aug 2012 13:32:11 +0200 Subject: [PATCH 0508/1590] Ignore tests/test.zip created by tests --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 39f2bcc37..0a9c02573 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ /_build /build /dist +tests/test.zip From 0d56f78a19902084714ebbdc960cee40f9ae8ea1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 21 Aug 2012 14:09:30 +0200 Subject: [PATCH 0509/1590] Revert "Make json imports 2.5-compatible again" This reverts commit e5a0dcb2d52e68e858db39c59ceb3aca4fc239d7. --- feincms/admin/tree_editor.py | 5 +---- feincms/content/table/models.py | 5 +---- feincms/contrib/fields.py | 5 +---- feincms/module/medialibrary/zip.py | 5 +---- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 2b897fe07..adac3149e 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -2,10 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -try: - import json -except ImportError: - from django.utils import simplejson as json # Python 2.5 +import json import logging from django.conf import settings as django_settings diff --git a/feincms/content/table/models.py b/feincms/content/table/models.py index 6fde427e2..fb7a617ce 100644 --- a/feincms/content/table/models.py +++ b/feincms/content/table/models.py @@ -1,7 +1,4 @@ -try: - import json -except ImportError: - from django.utils import simplejson as json # Python 2.5 +import json from django.db import models from django.utils.safestring import mark_safe diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index b8aa2427b..fea195bac 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -1,7 +1,4 @@ -try: - import json -except ImportError: - from django.utils import simplejson as json # Python 2.5 +import json import logging from django import forms diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 12ea15048..28b1712af 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -9,10 +9,7 @@ from __future__ import absolute_import -try: - import json -except ImportError: - from django.utils import simplejson as json # Python 2.5 +import json import zipfile import os import time From aba8297f897fa8fb71e3bc11e4216859485cf361 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 30 Aug 2012 20:43:29 +0200 Subject: [PATCH 0510/1590] Fix the assign mediafiles to category functionality --- feincms/module/medialibrary/modeladmins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index bd32e22f3..ca70ddd42 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -70,6 +70,7 @@ class AddCategoryForm(forms.Form): return render_to_response('admin/medialibrary/add_to_category.html', { 'mediafiles': queryset, 'category_form': form, + 'opts': modeladmin.model._meta, }, context_instance=RequestContext(request)) assign_category.short_description = _('Add selected media files to category') From 341c7e5e2df1c59f53689b4ae562fcb6cdad864e Mon Sep 17 00:00:00 2001 From: Stefan Reinhard <sr@feinheit.ch> Date: Mon, 3 Sep 2012 12:08:59 +0200 Subject: [PATCH 0511/1590] fix feincms cleanse function calls by converting them to instance methods --- feincms/content/richtext/models.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 4a123cc4b..f15c580ce 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -92,20 +92,20 @@ def render(self, **kwargs): def save(self, *args, **kwargs): # TODO: Move this to the form? if getattr(self, 'cleanse', False): - try: - # Passes the rich text content as first argument because - # the passed callable has been converted into a bound method - self.text = self.cleanse(self.text) - except TypeError: - # Call the original callable, does not pass the rich text - # content instance along - self.text = self.cleanse.im_func(self.text) + # Passes the rich text content as first argument because + # the passed callable has been converted into a bound method + self.text = self.cleanse(self.text) super(RichTextContent, self).save(*args, **kwargs) save.alters_data = True @classmethod def initialize_type(cls, cleanse=False): + def to_instance_method(func): + def func_im(self, *args, **kwargs): + return func(*args, **kwargs) + return func_im + if cleanse: # If cleanse is True use default cleanse method if cleanse == True: @@ -120,10 +120,10 @@ def initialize_type(cls, cleanse=False): DeprecationWarning, stacklevel=2) from feincms.utils.html.cleanse import cleanse_html - cls.cleanse = cleanse_html + cls.cleanse = to_instance_method(cleanse_html) # Otherwise use passed callable else: - cls.cleanse = cleanse + cls.cleanse = to_instance_method(cleanse) # TODO: Move this into somewhere more generic: if settings.FEINCMS_TIDY_HTML: From a4190b39ae470d2a9c42a970421e870a6d5a5b1c Mon Sep 17 00:00:00 2001 From: Simon Schmid <ssc@feinheit.ch> Date: Tue, 11 Sep 2012 13:10:36 +0200 Subject: [PATCH 0512/1590] s3storage raises a IOError, if the file is not found --- feincms/templatetags/feincms_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 8b85a3402..72a867dc1 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -81,7 +81,7 @@ def __unicode__(self): except (NotImplementedError, AttributeError): # storage does NOT support modified_time generate = False - except OSError: + except (OSError, IOError): # Someone might have delete the file return u'' From f3f81e46791b43711edb6a070161ff73baafd260 Mon Sep 17 00:00:00 2001 From: Raphael Jasjukaitis <r.jasjukaitis@raphaa.de> Date: Tue, 11 Sep 2012 21:01:17 +0200 Subject: [PATCH 0513/1590] Administration: If all elements in a region are deleted, the empty message is visible and it is possible adding new content types which are displayed correctly. --- feincms/static/feincms/item_editor.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 37bccb280..027f55b23 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -381,7 +381,6 @@ if(!Array.indexOf) { var id = item.find(".item-content > div").attr('id'); var modvar = id.replace(/_set-\d+$/, ''); var count = $('#id_'+modvar+'_set-TOTAL_FORMS').val(); - $('#id_'+modvar+'_set-TOTAL_FORMS').val(count-1); // remove form: item.find(".item-content").remove(); @@ -394,7 +393,12 @@ if(!Array.indexOf) { else{ // saved on server, don't remove form set_item_field_value(item,"delete-field","checked"); } - item.fadeOut(200); + item.fadeOut(200, function() { + region_item = $("#"+REGION_MAP[ACTIVE_REGION]+"_body"); + if (region_item.children("div.order-machine").children(":visible").length == 0) { + region_item.children("div.empty-machine-msg").show(); + } + }); } $(".popup_bg").remove(); }); From 43b37a5b362f05661691f608b42682c4648ff5ad Mon Sep 17 00:00:00 2001 From: Raphael Jasjukaitis <r.jasjukaitis@raphaa.de> Date: Wed, 12 Sep 2012 09:49:20 +0200 Subject: [PATCH 0514/1590] var added. --- feincms/static/feincms/item_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 027f55b23..7251769e3 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -394,7 +394,7 @@ if(!Array.indexOf) { set_item_field_value(item,"delete-field","checked"); } item.fadeOut(200, function() { - region_item = $("#"+REGION_MAP[ACTIVE_REGION]+"_body"); + var region_item = $("#"+REGION_MAP[ACTIVE_REGION]+"_body"); if (region_item.children("div.order-machine").children(":visible").length == 0) { region_item.children("div.empty-machine-msg").show(); } From b06142ff2ef04c250b7b04fb29ffcdff157d98e0 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Thu, 13 Sep 2012 09:12:20 +0200 Subject: [PATCH 0515/1590] FIX frontend_editing error introduced in dd087a9af2166cc942f4c80cd7c0cfd172440f71 cookie `frontend_editing` is set only user has permission --- feincms/module/page/processors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index e3b66e80c..d2d71ef88 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -32,14 +32,14 @@ def frontendediting_request_processor(page, request): if not 'frontend_editing' in request.GET: return + response = HttpResponseRedirect(request.path) if request.user.has_module_perms('page'): try: enable_fe = int(request.GET['frontend_editing']) > 0 except ValueError: enable_fe = False - response = HttpResponseRedirect(request.path) - response.set_cookie('frontend_editing', enable_fe) + response.set_cookie('frontend_editing', enable_fe) # Redirect to cleanup URLs return response From 9ff2df41f8418c04a42d618d893c77589bbe23d0 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Thu, 13 Sep 2012 09:12:58 +0200 Subject: [PATCH 0516/1590] Replace session for COOKIE for frontend_editing in other places --- feincms/models.py | 2 +- feincms/templatetags/feincms_tags.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index ad401c057..112aabfab 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -507,7 +507,7 @@ def fe_render(self, **kwargs): if 'request' in kwargs: request = kwargs['request'] - if request.session and request.session.get('frontend_editing'): + if request.COOKIES and request.COOKIES.get('frontend_editing'): return render_to_string('admin/feincms/fe_box.html', { 'content': self.render(**kwargs), 'identifier': self.fe_identifier(), diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index cb72dfaa2..b4bb76d18 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -56,7 +56,7 @@ def feincms_frontend_editing(cms_obj, request): {% feincms_frontend_editing feincms_page request %} """ - if hasattr(request, 'session') and request.session.get('frontend_editing'): + if hasattr(request, 'COOKIES') and request.COOKIES.get('frontend_editing'): context = template.RequestContext(request, { "feincms_page": cms_obj, }) From f809351325d2a0f7081ce0b24f6f7788472b2666 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Thu, 13 Sep 2012 09:19:37 +0200 Subject: [PATCH 0517/1590] Replace session to COOKIE for frontend_editing in tests too --- feincms/tests/page_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index c76257816..8dd36dd04 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -589,7 +589,7 @@ def test_15_frontend_editing(self): self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') request = Empty() - request.session = {'frontend_editing': True} + request.COOKIES = {'frontend_editing': True} self.assertTrue('class="fe_box"' in\ page.content.main[0].fe_render(request=request)) From 13fb3f8fea235e970c68326cc699ba7a50bb12f1 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Thu, 13 Sep 2012 09:19:57 +0200 Subject: [PATCH 0518/1590] Assure fe_tools is always on top with higher z-index --- feincms/static/feincms/frontend_editing.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/static/feincms/frontend_editing.css b/feincms/static/feincms/frontend_editing.css index d953189d0..208a0e734 100644 --- a/feincms/static/feincms/frontend_editing.css +++ b/feincms/static/feincms/frontend_editing.css @@ -9,7 +9,7 @@ } #fe_controls, #fe_tools { - z-index: 100; + z-index: 10000; background-color: white; /* CSS3 standard: */ opacity: 0.8; @@ -65,4 +65,4 @@ padding: 4px 5px; display: block; float: left; -} \ No newline at end of file +} From 4c4316fc29daafb4da0310742ff63289ae99fd1c Mon Sep 17 00:00:00 2001 From: Vaclav Klecanda <vencax77@gmail.com> Date: Thu, 13 Sep 2012 11:17:38 +0200 Subject: [PATCH 0519/1590] FLV suffix added among videos --- feincms/module/medialibrary/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 03bca576b..81bceb4d0 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -200,7 +200,7 @@ def delete_mediafile(self, name=None): MediaFileBase.register_filetypes( # Should we be using imghdr.what instead of extension guessing? ('image', _('Image'), lambda f: re.compile(r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), - ('video', _('Video'), lambda f: re.compile(r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv)$', re.IGNORECASE).search(f)), + ('video', _('Video'), lambda f: re.compile(r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv|flv)$', re.IGNORECASE).search(f)), ('audio', _('Audio'), lambda f: re.compile(r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), ('pdf', _('PDF document'), lambda f: f.lower().endswith('.pdf')), ('swf', _('Flash'), lambda f: f.lower().endswith('.swf')), From f311513da9513b8be0edb2ae28d6e3d21c320fb1 Mon Sep 17 00:00:00 2001 From: Stefan Reinhard <sr@feinheit.ch> Date: Mon, 3 Sep 2012 12:08:59 +0200 Subject: [PATCH 0520/1590] fix feincms cleanse function calls by converting them to instance methods --- feincms/content/richtext/models.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 4a123cc4b..f15c580ce 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -92,20 +92,20 @@ def render(self, **kwargs): def save(self, *args, **kwargs): # TODO: Move this to the form? if getattr(self, 'cleanse', False): - try: - # Passes the rich text content as first argument because - # the passed callable has been converted into a bound method - self.text = self.cleanse(self.text) - except TypeError: - # Call the original callable, does not pass the rich text - # content instance along - self.text = self.cleanse.im_func(self.text) + # Passes the rich text content as first argument because + # the passed callable has been converted into a bound method + self.text = self.cleanse(self.text) super(RichTextContent, self).save(*args, **kwargs) save.alters_data = True @classmethod def initialize_type(cls, cleanse=False): + def to_instance_method(func): + def func_im(self, *args, **kwargs): + return func(*args, **kwargs) + return func_im + if cleanse: # If cleanse is True use default cleanse method if cleanse == True: @@ -120,10 +120,10 @@ def initialize_type(cls, cleanse=False): DeprecationWarning, stacklevel=2) from feincms.utils.html.cleanse import cleanse_html - cls.cleanse = cleanse_html + cls.cleanse = to_instance_method(cleanse_html) # Otherwise use passed callable else: - cls.cleanse = cleanse + cls.cleanse = to_instance_method(cleanse) # TODO: Move this into somewhere more generic: if settings.FEINCMS_TIDY_HTML: From 9a0c6cde36d6aa9d08014029629bae7d2e4326b9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 19 Sep 2012 14:04:08 +0200 Subject: [PATCH 0521/1590] Reuse our own shorten_string method instead of truncate_words (deprecated) --- feincms/module/medialibrary/fields.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 4ee72784f..109d7ffe2 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -11,10 +11,10 @@ from django.db import models from django.utils.html import escape from django.utils.safestring import mark_safe -from django.utils.text import truncate_words from django.utils.translation import ugettext_lazy as _ from feincms.admin.item_editor import FeinCMSInline +from feincms.utils import shorten_string from .models import MediaFile from .thumbnail import admin_thumbnail @@ -29,7 +29,8 @@ def label_for_value(self, value): key = self.rel.get_related_field().name try: obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) - label = [u' <strong>%s</strong>' % escape(truncate_words(obj, 14))] + label = [u' <strong>%s</strong>' % escape( + shorten_string(unicode(obj)))] image = admin_thumbnail(obj) if image: From d6b00a3dd509a35ae7958b5fecc87ba942a5164b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 19 Sep 2012 14:20:18 +0200 Subject: [PATCH 0522/1590] FeinCMS v1.6.3 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 4d631445c..1a9d5d1a8 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 6, 2) +VERSION = (1, 6, 3) __version__ = '.'.join(map(str, VERSION)) From 4e32afd2b66ed733f13af4401247fa76c711577c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 19 Sep 2012 14:40:13 +0200 Subject: [PATCH 0523/1590] Work on release notes a bit --- docs/releases/1.7.rst | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index 9c9631fba..0c4420bf8 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -13,6 +13,8 @@ know about their related model admin classes. The new module :py:mod:`feincms.extensions` contains mixins and base classes - their purpose is as follows: +**TODO move this somewhere else, this isn't release notes material** + .. class:: feincms.extensions.ExtensionsMixin This mixin provides the ``register_extensions`` method which is the place @@ -79,8 +81,8 @@ View code refactor Made views, content type and request / response processors reusable. -The legacy views at :py:mod:`feincms.views.legacy` did were considered -unhelpful and were removed. +The legacy views at :py:mod:`feincms.views.legacy` were considered unhelpful +and were removed. Backwards-incompatible changes @@ -132,6 +134,19 @@ Removal of deprecated features ``admin/content/mediafile/init.html`` has been deleted. +Nested ``ContentObjectMixin`` processing +---------------------------------------- + +FeinCMS now supports nested :py:class:`feincms.models.Base` subclasses +on a page, i.e. a content type with a ``process`` method inside an elephantblog +entry inside an application content. It's up to you to decide if this makes +sense or not -- + +Because of that, ``request._feincms_extra_context['extra_path']`` is now a +list, where the last element is always the remainder of the URL which is +relevant for the current content type. + + New deprecations ---------------- @@ -150,6 +165,14 @@ Notable features and improvements ``register_extension`` methods have been removed. Additionally, the model admin classes are not imported inside the ``models.py`` files anymore. +* The setting ``FEINCMS_USE_PAGE_ADMIN`` can be set to false to prevent + registration of the page model with the administration. This is especially + useful if you only want to reuse parts of the page module. + +* Various classes in :py:mod:`feincms.module.page` do not hardcode the page + class anymore; hooks are provided to use your own models instead. Please + refer to the source for additional information. + Bugfixes ======== @@ -164,6 +187,12 @@ Bugfixes * :py:func:`feincms.utils.get_object` knows how to import modules, not only objects inside modules now. +* The order and priority values for pages have been fixed when generating + sitemaps. + +* Various ``save`` and ``delete`` methods now come with ``alters_data=True`` + to prevent their use in templates. + Compatibility with Django and other apps ======================================== From 72a520f10ca5f5fb73b832dccb587ca993f5dbab Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 19 Sep 2012 19:28:59 +0200 Subject: [PATCH 0524/1590] translations: Call the original get_redirect_to_target instead of accessing redirect_to directly This makes it possible to chain various redirect_to handlers. --- feincms/module/extensions/translations.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 044756418..4cf1c7599 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -134,6 +134,7 @@ def register(cls, admin_cls): key='translations') if hasattr(cls, 'get_redirect_to_target'): + original_get_redirect_to_target = cls.get_redirect_to_target @monkeypatch_method(cls) def get_redirect_to_target(self, request): """ @@ -142,7 +143,7 @@ def get_redirect_to_target(self, request): to the user's language. This way, one can easily implement a localized "/"-url to welcome page redirection. """ - target = self.redirect_to + target = original_get_redirect_to_target(self, request) if target and target.find('//') == -1: # Not an offsite link http://bla/blubb try: page = cls.objects.page_for_path(target) From 266372c4f141d48a077abdcdacb78faa27f49aae Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 19 Sep 2012 19:30:13 +0200 Subject: [PATCH 0525/1590] Allow specifying PKs of pages as `redirect_to` Additionally, use a raw_id_fields widget to easily pick a redirection target. --- feincms/module/page/forms.py | 18 ++++++++++++++++-- feincms/module/page/modeladmins.py | 5 +++++ feincms/module/page/models.py | 14 +++++++++++++- feincms/static/feincms/style.css | 4 ++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index d0f232867..d376d1ac5 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -5,6 +5,7 @@ from __future__ import absolute_import from django import forms +from django.contrib.admin.widgets import ForeignKeyRawIdWidget from django.contrib.sites.models import Site from django.forms.models import model_to_dict from django.forms.util import ErrorList @@ -72,15 +73,28 @@ def __init__(self, *args, **kwargs): except (AttributeError, Page.DoesNotExist): pass + # Not required, only a nice-to-have for the `redirect_to` field + modeladmin = kwargs.pop('modeladmin', None) super(PageAdminForm, self).__init__(*args, **kwargs) + if modeladmin: + # Note: Using `parent` is not strictly correct, but we can be + # sure that `parent` always points to another page instance, + # and that's good enough for us. + self.fields['redirect_to'].widget = ForeignKeyRawIdWidget( + Page._meta.get_field('parent').rel, + modeladmin.admin_site) + if 'instance' in kwargs: choices = [] for key, template in kwargs['instance'].TEMPLATE_CHOICES: template = kwargs['instance']._feincms_templates[key] if template.preview_image: choices.append((template.key, - mark_safe(u'<img src="%s" alt="%s" /> %s' % ( - template.preview_image, template.key, template.title)))) + mark_safe(u'<img src="%s" alt="%s" /> %s' % ( + template.preview_image, + template.key, + template.title, + )))) else: choices.append((template.key, template.title)) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index b3c00daf5..00802ddd2 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -10,6 +10,7 @@ from django.contrib import admin from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect +from django.utils.functional import curry from django.utils.translation import ugettext_lazy as _ from feincms import ensure_completely_loaded @@ -88,6 +89,10 @@ def __init__(self, *args, **kwargs): in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) + def get_form(self, *args, **kwargs): + form = super(PageAdmin, self).get_form(*args, **kwargs) + return curry(form, modeladmin=self) + def _actions_column(self, page): editable = getattr(page, 'feincms_editable', True) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index eaddcfb5f..04a15e150 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -146,7 +146,8 @@ class Page(create_base_model(MPTTModel)): override_url = models.CharField(_('override URL'), max_length=300, blank=True, help_text=_('Override the target URL. Be sure to include slashes at the beginning and at the end if it is a local URL. This affects both the navigation and subpages\' URLs.')) redirect_to = models.CharField(_('redirect to'), max_length=300, blank=True, - help_text=_('Target URL for automatic redirects.')) + help_text=_('Target URL for automatic redirects' + ' or the primary key of a page.')) _cached_url = models.CharField(_('Cached URL'), max_length=300, blank=True, editable=False, default='', db_index=True) @@ -356,6 +357,17 @@ def get_redirect_to_target(self, request): """ This might be overriden/extended by extension modules. """ + + if re.match(r'^\d+$', self.redirect_to): + # It might the primary key of a page + try: + page = self.__class__.objects.get(pk=int(self.redirect_to)) + return page.get_absolute_url() + except (ValueError, TypeError): + pass + except (self.DoesNotExist): + return None + return self.redirect_to @classmethod diff --git a/feincms/static/feincms/style.css b/feincms/static/feincms/style.css index 7a8ecc1d8..08c9c19ae 100644 --- a/feincms/static/feincms/style.css +++ b/feincms/static/feincms/style.css @@ -321,3 +321,7 @@ div.order-machine div.inline-related > h3{ .hidden-form-row{ display: none; } + + +/* various overrides */ +#id_redirect_to { width: 20em; } /* raw_id_fields act-a-like for redirect_to */ From efc024557e45bf3ce832e8d2bfe543ed6ce396d8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 09:17:55 +0200 Subject: [PATCH 0526/1590] One TODO down --- feincms/admin/tree_editor.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index adac3149e..883017fa8 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -314,13 +314,9 @@ def _toggle_boolean(self, request): # Weed out unchanged cells to keep the updates small. This assumes # that the order a possible get_descendents() returns does not change # before and after toggling this attribute. Unlikely, but still... - d = [] - for a, b in zip(before_data, data): - if a != b: - d.append(b) - - # TODO: Shorter: [ y for x,y in zip(a,b) if x!=y ] - return HttpResponse(json.dumps(d), content_type="application/json") + return HttpResponse(json.dumps( + [b for a, b in zip(before_data, data) if a != b] + ), content_type="application/json") def get_changelist(self, request, **kwargs): return ChangeList From 64b836c7cd81b64a28c32e1e4baa95693f16de60 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 09:18:42 +0200 Subject: [PATCH 0527/1590] This is sufficient for a comment in the documentation --- docs/integration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integration.rst b/docs/integration.rst index 66676b49b..7cadf6b9f 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -239,7 +239,7 @@ of any template rendering calls: from news.models import Entry def entry_list(request): - # TODO add pagination here + # Pagination should probably be added here return 'news/entry_list.html', {'object_list': Entry.objects.all()} def entry_detail(request, slug): From bf3162eb820ad4f81cd1ef6c01ff10f094478f5d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 09:22:05 +0200 Subject: [PATCH 0528/1590] all_of_type does not order results too much, and that's alright --- feincms/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index d15294c7f..072f8428f 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -231,6 +231,10 @@ def all_of_type(self, type_or_tuple): Returns all content type instances belonging to the type or types passed. If you want to filter for several types at the same time, type must be a tuple. + + The content type instances are sorted by their ``ordering`` value, + but that isn't necessarily meaningful if the same content type exists + in different regions. """ content_list = [] @@ -242,7 +246,6 @@ def all_of_type(self, type_or_tuple): if any(issubclass(type, t) for t in type_or_tuple): content_list.extend(contents) - # TODO: Sort content types by region? return sorted(content_list, key=lambda c: c.ordering) def _get_media(self): From 4fa140d63d5f179477d3c89aa64f90ac62466e9a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 09:25:53 +0200 Subject: [PATCH 0529/1590] Actually remove the register_extension methods as the release notes say --- feincms/module/blog/models.py | 4 ---- feincms/module/medialibrary/models.py | 6 +----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index dd699581c..8300d0412 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -54,10 +54,6 @@ def save(self, *args, **kwargs): def get_absolute_url(self): return ('blog_entry_detail', (self.id,), {}) - @classmethod - def register_extension(cls, register_fn): - register_fn(cls, EntryAdmin) - signals.post_syncdb.connect(check_database_schema(Entry, __name__), weak=False) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 81bceb4d0..bcdcab2e1 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -215,11 +215,7 @@ def delete_mediafile(self, name=None): # ------------------------------------------------------------------------ class MediaFile(MediaFileBase): - @classmethod - def register_extension(cls, register_fn): - from .admin import MediaFileAdmin - - register_fn(cls, MediaFileAdmin) + pass @receiver(post_delete, sender=MediaFile) def _mediafile_post_delete(sender, instance, **kwargs): From df861a9ac3a4713b298a5322b71d4a69f2aa7f1c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 09:28:56 +0200 Subject: [PATCH 0530/1590] Move FEINCMS_USE_PAGE_ADMIN to feincms.settings --- feincms/default_settings.py | 5 +++++ feincms/module/page/admin.py | 6 ++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 73439d1cb..66af9e4fd 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -69,6 +69,11 @@ FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS = getattr(settings, 'FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS', False) +#: When enabled, the page module is automatically registered with Django's +#: default admin site (this is activated by default). +FEINCMS_USE_PAGE_ADMIN = getattr(settings, + 'FEINCMS_USE_PAGE_ADMIN', True) + # ------------------------------------------------------------------------ # Various settings diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index c22942200..40fb38fd2 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -4,19 +4,17 @@ from __future__ import absolute_import -from django.conf import settings from django.contrib import admin from django.core.exceptions import ImproperlyConfigured from django.db.models import FieldDoesNotExist -from feincms import ensure_completely_loaded +from feincms import ensure_completely_loaded, settings from .models import Page from .modeladmins import PageAdmin # ------------------------------------------------------------------------ -# XXX move this setting to feincms.settings? -if getattr(settings, 'FEINCMS_USE_PAGE_ADMIN', True): +if settings.FEINCMS_USE_PAGE_ADMIN: ensure_completely_loaded() try: Page._meta.get_field('template_key') From 929e7de80f51ad4109fa26b56ee15cbf5c9f5a96 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 09:33:09 +0200 Subject: [PATCH 0531/1590] Move TODO where it belongs --- feincms/module/extensions/ct_tracker.py | 3 ++- feincms/module/page/models.py | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 43801ff1f..870607194 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -122,7 +122,8 @@ def tree_post_save_handler(sender, instance, **kwargs): Clobber the _ct_inventory attribute of this object and all sub-objects on save. """ - + # TODO: Does not find everything it should when ContentProxy content + # inheritance has been customized. instance.get_descendants(include_self=True).update(_ct_inventory=None) # ------------------------------------------------------------------------ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index e9fafd90c..4863829d0 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -255,8 +255,6 @@ def save(self, *args, **kwargs): if self._cached_url == self._original_cached_url: return - # TODO: Does not find everything it should when ContentProxy content - # inheritance has been customized. pages = self.get_descendants().order_by('lft') for page in pages: From 5f27d23150552e4256620f1f4da8c4354e351dca Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 09:39:27 +0200 Subject: [PATCH 0532/1590] Emit a log message when render level>10 --- feincms/templatetags/feincms_tags.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index b4bb76d18..66c47913e 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +import logging + from django import template from django.template.loader import render_to_string @@ -16,7 +18,9 @@ def _render_content(content, **kwargs): if request is not None: level = getattr(request, 'feincms_render_level', 0) if level > 10: - # TODO: Log this + logging.getLogger('feincms').error( + 'Refusing to render %r, render level is already %s' % ( + content, level)) return setattr(request, 'feincms_render_level', level + 1) From abf369730174db5efcc30e85d29dacc645e82dcf Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 11:18:18 +0200 Subject: [PATCH 0533/1590] PageAdminForm: Use self.page_model instead of Page --- feincms/module/page/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index e18c26e89..99b86d738 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -89,7 +89,7 @@ def __init__(self, *args, **kwargs): # sure that `parent` always points to another page instance, # and that's good enough for us. self.fields['redirect_to'].widget = ForeignKeyRawIdWidget( - Page._meta.get_field('parent').rel, + self.page_model._meta.get_field('parent').rel, modeladmin.admin_site) if 'instance' in kwargs: From a65d3663d611d53ad7c9b70d9cb99f78b5663aa5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 12:19:18 +0200 Subject: [PATCH 0534/1590] RedirectTo: Store page.page:PK instead of PK This protocol ensures that we do not have to support pure PKs until the end of the world. Thanks to mjl for the suggestion. --- feincms/module/page/forms.py | 33 ++++++++++++++++++++++++++++++++- feincms/module/page/models.py | 33 ++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 99b86d738..16c96a01c 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -4,19 +4,43 @@ from __future__ import absolute_import +import re + from django import forms from django.contrib.admin.widgets import ForeignKeyRawIdWidget from django.contrib.sites.models import Site +from django.db.models.loading import get_model from django.forms.models import model_to_dict from django.forms.util import ErrorList from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from feincms import ensure_completely_loaded +from feincms.utils import shorten_string from mptt.forms import MPTTAdminForm +class RedirectToWidget(ForeignKeyRawIdWidget): + def label_for_value(self, value): + match = re.match( + r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$', + value) + + if value: + matches = match.groupdict() + model = get_model(matches['app_label'], matches['module_name']) + try: + instance = model._default_manager.get(pk=int(matches['pk'])) + return u' <strong>%s (%s)</strong>' % (instance, + instance.get_absolute_url()) + + except model.DoesNotExist: + pass + + return u'' + + # ------------------------------------------------------------------------ class PageAdminForm(MPTTAdminForm): never_copy_fields = ('title', 'slug', 'parent', 'active', 'override_url', @@ -88,7 +112,7 @@ def __init__(self, *args, **kwargs): # Note: Using `parent` is not strictly correct, but we can be # sure that `parent` always points to another page instance, # and that's good enough for us. - self.fields['redirect_to'].widget = ForeignKeyRawIdWidget( + self.fields['redirect_to'].widget = RedirectToWidget( self.page_model._meta.get_field('parent').rel, modeladmin.admin_site) @@ -158,6 +182,13 @@ def clean(self): self._errors['active'] = ErrorList([_('This URL is already taken by another active page.')]) del cleaned_data['active'] + # Convert PK in redirect_to field to something nicer for the future + redirect_to = cleaned_data.get('redirect_to') + if redirect_to and re.match(r'^\d+$', redirect_to): + opts = self.page_model._meta + cleaned_data['redirect_to'] = '%s.%s:%s' % ( + opts.app_label, opts.module_name, redirect_to) + return cleaned_data # ------------------------------------------------------------------------ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 4863829d0..8ed335b7b 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -8,6 +8,7 @@ from django.conf import settings as django_settings from django.db import models from django.db.models import Q, signals +from django.db.models.loading import get_model from django.http import Http404 from django.utils.translation import ugettext_lazy as _ from django.db.transaction import commit_on_success @@ -319,15 +320,29 @@ def get_redirect_to_target(self, request): This might be overriden/extended by extension modules. """ - if re.match(r'^\d+$', self.redirect_to): - # It might the primary key of a page - try: - page = self.__class__.objects.get(pk=int(self.redirect_to)) - return page.get_absolute_url() - except (ValueError, TypeError): - pass - except (self.DoesNotExist): - return None + if not self.redirect_to: + return u'' + + # It might be an identifier for a different object + match = re.match( + r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$', + self.redirect_to) + + # It's not, oh well. + if not match: + return self.redirect_to + + matches = match.groupdict() + model = get_model(matches['app_label'], matches['module_name']) + + if not model: + return self.redirect_to + + try: + instance = model._default_manager.get(pk=int(matches['pk'])) + return instance.get_absolute_url() + except models.ObjectDoesNotExist: + pass return self.redirect_to From 3694ac8835202b1405094d8f8a92c20140b8e822 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 20 Sep 2012 13:45:36 +0200 Subject: [PATCH 0535/1590] Typofix --- feincms/module/page/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 16c96a01c..63576f421 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -27,7 +27,7 @@ def label_for_value(self, value): r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$', value) - if value: + if match: matches = match.groupdict() model = get_model(matches['app_label'], matches['module_name']) try: From 960a6478de7c2a94f637ddab538ffc199efe56a1 Mon Sep 17 00:00:00 2001 From: Maarten Draijer <maarten@madra.nl> Date: Wed, 26 Sep 2012 11:11:13 +0200 Subject: [PATCH 0536/1590] Fix wrongly indented if statement. --- feincms/module/page/modeladmins.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index b3c00daf5..27bfcf0e2 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -83,8 +83,8 @@ def __init__(self, *args, **kwargs): if not f.name.startswith('_') and not f.name in ('id', 'lft', 'rght', 'tree_id', 'level') and \ not f.auto_created and not f.name in present_fields and f.editable: self.unknown_fields.append(f.name) - if not f.editable: - self.readonly_fields.append(f.name) + if not f.editable: + self.readonly_fields.append(f.name) in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) From 89ab670be12db7f5c8d7e12aaeaf64213e2cb080 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 28 Sep 2012 08:51:08 +0200 Subject: [PATCH 0537/1590] No, we do not want to look inside files, that's a project-specific decision --- feincms/tests/page_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 9580e622c..6d8a10138 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -1235,7 +1235,6 @@ def test_29_medialibrary_admin(self): stats = list(MediaFile.objects.values_list('type', flat=True)) self.assertEqual(stats.count('image'), 12) self.assertEqual(stats.count('other'), 0) - # XXX: Test mediafile type detection some more? def test_30_context_processors(self): self.create_default_page_set() From 6b30af3bb78c558cef5dff97ed23604321371e46 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 28 Sep 2012 11:58:03 +0200 Subject: [PATCH 0538/1590] Update the documentation to the current MPTT state-of-the-art Fixes #353, thanks typeshige for the report! --- docs/admin.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/admin.rst b/docs/admin.rst index 4c59146cd..20fc8a99e 100644 --- a/docs/admin.rst +++ b/docs/admin.rst @@ -24,13 +24,16 @@ for this to work. Usage is as follows:: from django.db import models + from mptt.fields import TreeForeignKey + from mptt.models import MPTTModel - class YourModel(models.Model): + class YourModel(MPTTModel): # model field definitions - class Meta: - ordering = ['tree_id', 'lft'] # The TreeEditor needs this ordering definition + parent = TreeForeignKey('self', null=True, blank=True, related_name='children') + class Meta: + ordering = ['tree_id', 'lft'] # The TreeEditor needs this ordering definition And inside your ``admin.py`` file:: From 1eca224717a6a4bd3c4d51dac943f5301a8ed684 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Tue, 2 Oct 2012 11:32:36 +0200 Subject: [PATCH 0539/1590] Update jquery to 1.8.1, jquery-ui to 1.8.22 --- feincms/static/feincms/jquery-1.7.1.min.js | 4 - feincms/static/feincms/jquery-1.8.1.min.js | 2 + .../feincms/jquery-ui-1.8.16.custom.min.js | 791 ------------------ .../feincms/jquery-ui-1.8.22.custom.min.js | 125 +++ .../templates/admin/feincms/fe_editor.html | 4 +- .../admin/feincms/fe_editor_done.html | 4 +- feincms/templates/admin/feincms/fe_tools.html | 2 +- .../templates/admin/feincms/item_editor.html | 4 +- .../templates/admin/feincms/tree_editor.html | 4 +- 9 files changed, 136 insertions(+), 804 deletions(-) delete mode 100644 feincms/static/feincms/jquery-1.7.1.min.js create mode 100644 feincms/static/feincms/jquery-1.8.1.min.js delete mode 100755 feincms/static/feincms/jquery-ui-1.8.16.custom.min.js create mode 100755 feincms/static/feincms/jquery-ui-1.8.22.custom.min.js diff --git a/feincms/static/feincms/jquery-1.7.1.min.js b/feincms/static/feincms/jquery-1.7.1.min.js deleted file mode 100644 index 198b3ff07..000000000 --- a/feincms/static/feincms/jquery-1.7.1.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.7.1 jquery.com | jquery.org/license */ -(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; -f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() -{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-1.8.1.min.js b/feincms/static/feincms/jquery-1.8.1.min.js new file mode 100644 index 000000000..e7f2a292b --- /dev/null +++ b/feincms/static/feincms/jquery-1.8.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v@1.8.1 jquery.com | jquery.org/license */ +(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.1",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":a.toString().replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||f.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return typeof a=="object"?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length||!d)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||++p.uuid:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")===0&&(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)~f.indexOf(" "+b[g]+" ")||(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>-1)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,""+d),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,k,l,m,n=(p._data(this,"events")||{})[c.type]||[],o=n.delegateCount,q=[].slice.call(arguments),r=!c.exclusive&&!c.namespace,s=p.event.special[c.type]||{},t=[];q[0]=c,c.delegateTarget=this;if(s.preDispatch&&s.preDispatch.call(this,c)===!1)return;if(o&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<o;d++)k=n[d],l=k.selector,h[l]===b&&(h[l]=p(l,this).index(f)>=0),h[l]&&j.push(k);j.length&&t.push({elem:f,matches:j})}n.length>o&&t.push({elem:this,matches:n.slice(o)});for(d=0;d<t.length&&!c.isPropagationStopped();d++){i=t[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){k=i.matches[e];if(r||!c.namespace&&!k.namespace||c.namespace_re&&c.namespace_re.test(k.namespace))c.data=k.data,c.handleObj=k,g=((p.event.special[k.origType]||{}).handle||k.handler).apply(i.elem,q),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return s.postDispatch&&s.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function $(a,b,c,d){c=c||[],b=b||q;var e,f,g,j,k=b.nodeType;if(k!==1&&k!==9)return[];if(!a||typeof a!="string")return c;g=h(b);if(!g&&!d)if(e=L.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&i(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return u.apply(c,t.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&X&&b.getElementsByClassName)return u.apply(c,t.call(b.getElementsByClassName(j),0)),c}return bk(a,b,c,d,g)}function _(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function ba(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bb(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bc(a,b,c,d){var e,g,h,i,j,k,l,m,n,p,r=!c&&b!==q,s=(r?"<s>":"")+a.replace(H,"$1<s>"),u=y[o][s];if(u)return d?0:t.call(u,0);j=a,k=[],m=0,n=f.preFilter,p=f.filter;while(j){if(!e||(g=I.exec(j)))g&&(j=j.slice(g[0].length),h.selector=l),k.push(h=[]),l="",r&&(j=" "+j);e=!1;if(g=J.exec(j))l+=g[0],j=j.slice(g[0].length),e=h.push({part:g.pop().replace(H," "),string:g[0],captures:g});for(i in p)(g=S[i].exec(j))&&(!n[i]||(g=n[i](g,b,c)))&&(l+=g[0],j=j.slice(g[0].length),e=h.push({part:i,string:g.shift(),captures:g}));if(!e)break}return l&&(h.selector=l),d?j.length:j?$.error(a):t.call(y(s,k),0)}function bd(a,b,e,f){var g=b.dir,h=s++;return a||(a=function(a){return a===e}),b.first?function(b){while(b=b[g])if(b.nodeType===1)return a(b)&&b}:f?function(b){while(b=b[g])if(b.nodeType===1&&a(b))return b}:function(b){var e,f=h+"."+c,i=f+"."+d;while(b=b[g])if(b.nodeType===1){if((e=b[o])===i)return b.sizset;if(typeof e=="string"&&e.indexOf(f)===0){if(b.sizset)return b}else{b[o]=i;if(a(b))return b.sizset=!0,b;b.sizset=!1}}}}function be(a,b){return a?function(c){var d=b(c);return d&&a(d===!0?c:d)}:b}function bf(a,b,c){var d,e,g=0;for(;d=a[g];g++)f.relative[d.part]?e=bd(e,f.relative[d.part],b,c):e=be(e,f.filter[d.part].apply(null,d.captures.concat(b,c)));return e}function bg(a){return function(b){var c,d=0;for(;c=a[d];d++)if(c(b))return!0;return!1}}function bh(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)$(a,b[e],c,d)}function bi(a,b,c,d,e,g){var h,i=f.setFilters[b.toLowerCase()];return i||$.error(b),(a||!(h=e))&&bh(a||"*",d,h=[],e),h.length>0?i(h,c,g):[]}function bj(a,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s=0,t=a.length,v=S.POS,w=new RegExp("^"+v.source+"(?!"+A+")","i"),x=function(){var a=1,c=arguments.length-2;for(;a<c;a++)arguments[a]===b&&(n[a]=b)};for(;s<t;s++){f=a[s],g="",m=e;for(h=0,i=f.length;h<i;h++){j=f[h],k=j.string;if(j.part==="PSEUDO"){v.exec(""),l=0;while(n=v.exec(k)){o=!0,p=v.lastIndex=n.index+n[0].length;if(p>l){g+=k.slice(l,n.index),l=p,q=[c],J.test(g)&&(m&&(q=m),m=e);if(r=O.test(g))g=g.slice(0,-5).replace(J,"$&*"),l++;n.length>1&&n[0].replace(w,x),m=bi(g,n[1],n[2],q,m,r)}g=""}}o||(g+=k),o=!1}g?J.test(g)?bh(g,m||[c],d,e):$(g,c,d,e?e.concat(m):m):u.apply(d,m)}return t===1?d:$.uniqueSort(d)}function bk(a,b,e,g,h){a=a.replace(H,"$1");var i,k,l,m,n,o,p,q,r,s,v=bc(a,b,h),w=b.nodeType;if(S.POS.test(a))return bj(v,b,e,g);if(g)i=t.call(g,0);else if(v.length===1){if((o=t.call(v[0],0)).length>2&&(p=o[0]).part==="ID"&&w===9&&!h&&f.relative[o[1].part]){b=f.find.ID(p.captures[0].replace(R,""),b,h)[0];if(!b)return e;a=a.slice(o.shift().string.length)}r=(v=N.exec(o[0].string))&&!v.index&&b.parentNode||b,q="";for(n=o.length-1;n>=0;n--){p=o[n],s=p.part,q=p.string+q;if(f.relative[s])break;if(f.order.test(s)){i=f.find[s](p.captures[0].replace(R,""),r,h);if(i==null)continue;a=a.slice(0,a.length-q.length)+q.replace(S[s],""),a||u.apply(e,t.call(i,0));break}}}if(a){k=j(a,b,h),c=k.dirruns++,i==null&&(i=f.find.TAG("*",N.test(a)&&b.parentNode||b));for(n=0;m=i[n];n++)d=k.runs++,k(m)&&e.push(m)}return e}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=a.document,r=q.documentElement,s=0,t=[].slice,u=[].push,v=function(a,b){return a[o]=b||!0,a},w=function(){var a={},b=[];return v(function(c,d){return b.push(c)>f.cacheLength&&delete a[b.shift()],a[c]=d},a)},x=w(),y=w(),z=w(),A="[\\x20\\t\\r\\n\\f]",B="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",C=B.replace("w","w#"),D="([*^$|!~]?=)",E="\\["+A+"*("+B+")"+A+"*(?:"+D+A+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+C+")|)|)"+A+"*\\]",F=":("+B+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+E+")|[^:]|\\\\.)*|.*))\\)|)",G=":(nth|eq|gt|lt|first|last|even|odd)(?:\\(((?:-\\d)?\\d*)\\)|)(?=[^-]|$)",H=new RegExp("^"+A+"+|((?:^|[^\\\\])(?:\\\\.)*)"+A+"+$","g"),I=new RegExp("^"+A+"*,"+A+"*"),J=new RegExp("^"+A+"*([\\x20\\t\\r\\n\\f>+~])"+A+"*"),K=new RegExp(F),L=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,M=/^:not/,N=/[\x20\t\r\n\f]*[+~]/,O=/:not\($/,P=/h\d/i,Q=/input|select|textarea|button/i,R=/\\(?!\\)/g,S={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),NAME:new RegExp("^\\[name=['\"]?("+B+")['\"]?\\]"),TAG:new RegExp("^("+B.replace("w","w*")+")"),ATTR:new RegExp("^"+E),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|nth|last|first)-child(?:\\("+A+"*(even|odd|(([+-]|)(\\d*)n|)"+A+"*(?:([+-]|)"+A+"*(\\d+)|))"+A+"*\\)|)","i"),POS:new RegExp(G,"ig"),needsContext:new RegExp("^"+A+"*[>+~]|"+G,"i")},T=function(a){var b=q.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},U=T(function(a){return a.appendChild(q.createComment("")),!a.getElementsByTagName("*").length}),V=T(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),W=T(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),X=T(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),Y=T(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",r.insertBefore(a,r.firstChild);var b=q.getElementsByName&&q.getElementsByName(o).length===2+q.getElementsByName(o+0).length;return e=!q.getElementById(o),r.removeChild(a),b});try{t.call(r.childNodes,0)[0].nodeType}catch(Z){t=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}$.matches=function(a,b){return $(a,null,null,b)},$.matchesSelector=function(a,b){return $(b,null,null,[a]).length>0},g=$.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=g(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=g(b);return c},h=$.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},i=$.contains=r.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:r.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},$.attr=function(a,b){var c,d=h(a);return d||(b=b.toLowerCase()),f.attrHandle[b]?f.attrHandle[b](a):W||d?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},f=$.selectors={cacheLength:50,createPseudo:v,match:S,order:new RegExp("ID|TAG"+(Y?"|NAME":"")+(X?"|CLASS":"")),attrHandle:V?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:e?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:U?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(R,""),a[3]=(a[4]||a[5]||"").replace(R,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||$.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&$.error(a[0]),a},PSEUDO:function(a,b,c){var d,e;if(S.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(d=a[4])K.test(d)&&(e=bc(d,b,c,!0))&&(e=d.indexOf(")",d.length-e)-d.length)&&(d=d.slice(0,e),a[0]=a[0].slice(0,e)),a[2]=d;return a.slice(0,3)}},filter:{ID:e?function(a){return a=a.replace(R,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(R,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(R,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=x[o][a];return b||(b=x(a,new RegExp("(^|"+A+")"+a+"("+A+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return b?function(d){var e=$.attr(d,a),f=e+"";if(e==null)return b==="!=";switch(b){case"=":return f===c;case"!=":return f!==c;case"^=":return c&&f.indexOf(c)===0;case"*=":return c&&f.indexOf(c)>-1;case"$=":return c&&f.substr(f.length-c.length)===c;case"~=":return(" "+f+" ").indexOf(c)>-1;case"|=":return f===c||f.substr(0,c.length+1)===c+"-"}}:function(b){return $.attr(b,a)!=null}},CHILD:function(a,b,c,d){if(a==="nth"){var e=s++;return function(a){var b,f,g=0,h=a;if(c===1&&d===0)return!0;b=a.parentNode;if(b&&(b[o]!==e||!a.sizset)){for(h=b.firstChild;h;h=h.nextSibling)if(h.nodeType===1){h.sizset=++g;if(h===a)break}b[o]=e}return f=a.sizset-d,c===0?f===0:f%c===0&&f/c>=0}}return function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b,c,d){var e,g=f.pseudos[a]||f.pseudos[a.toLowerCase()];return g||$.error("unsupported pseudo: "+a),g[o]?g(b,c,d):g.length>1?(e=[a,a,"",b],function(a){return g(a,0,e)}):g}},pseudos:{not:v(function(a,b,c){var d=j(a.replace(H,"$1"),b,c);return function(a){return!d(a)}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!f.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},contains:v(function(a){return function(b){return(b.textContent||b.innerText||g(b)).indexOf(a)>-1}}),has:v(function(a){return function(b){return $(a,b).length>0}}),header:function(a){return P.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:_("radio"),checkbox:_("checkbox"),file:_("file"),password:_("password"),image:_("image"),submit:ba("submit"),reset:ba("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return Q.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b,c){return c?a.slice(1):[a[0]]},last:function(a,b,c){var d=a.pop();return c?a:[d]},even:function(a,b,c){var d=[],e=c?1:0,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},odd:function(a,b,c){var d=[],e=c?0:1,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},lt:function(a,b,c){return c?a.slice(+b):a.slice(0,+b)},gt:function(a,b,c){return c?a.slice(0,+b+1):a.slice(+b+1)},eq:function(a,b,c){var d=a.splice(+b,1);return c?a:d}}},k=r.compareDocumentPosition?function(a,b){return a===b?(l=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return l=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bb(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bb(e[j],f[j]);return j===c?bb(a,f[j],-1):bb(e[j],b,1)},[0,0].sort(k),m=!l,$.uniqueSort=function(a){var b,c=1;l=m,a.sort(k);if(l)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},$.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},j=$.compile=function(a,b,c){var d,e,f,g=z[o][a];if(g&&g.context===b)return g;d=bc(a,b,c);for(e=0,f=d.length;e<f;e++)d[e]=bf(d[e],b,c);return g=z(a,bg(d)),g.context=b,g.runs=g.dirruns=0,g},q.querySelectorAll&&function(){var a,b=bk,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[],f=[":active"],g=r.matchesSelector||r.mozMatchesSelector||r.webkitMatchesSelector||r.oMatchesSelector||r.msMatchesSelector;T(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+A+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),T(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+A+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=e.length&&new RegExp(e.join("|")),bk=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a)))if(d.nodeType===9)try{return u.apply(f,t.call(d.querySelectorAll(a),0)),f}catch(i){}else if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){var j,k,l,m=d.getAttribute("id"),n=m||o,p=N.test(a)&&d.parentNode||d;m?n=n.replace(c,"\\$&"):d.setAttribute("id",n),j=bc(a,d,h),n="[id='"+n+"']";for(k=0,l=j.length;k<l;k++)j[k]=n+j[k].selector;try{return u.apply(f,t.call(p.querySelectorAll(j.join(",")),0)),f}catch(i){}finally{m||d.removeAttribute("id")}}return b(a,d,f,g,h)},g&&(T(function(b){a=g.call(b,"div");try{g.call(b,"[test!='']:sizzle"),f.push(S.PSEUDO.source,S.POS.source,"!=")}catch(c){}}),f=new RegExp(f.join("|")),$.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!h(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=g.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return $(c,null,null,[b]).length>0})}(),f.setFilters.nth=f.setFilters.eq,f.filters=f.pseudos,$.attr=p.attr,p.find=$,p.expr=$.selectors,p.expr[":"]=p.expr.pseudos,p.unique=$.uniqueSort,p.text=$.getText,p.isXMLDoc=$.isXML,p.contains=$.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{cj=f.href}catch(cy){cj=e.createElement("a"),cj.href="",cj=cj.href}ck=ct.exec(cj.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:cj,isLocal:cn.test(ck[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=""+(c||y),k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,ck[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase()),l.crossDomain=!(!i||i[1]==ck[1]&&i[2]==ck[2]&&(i[3]||(i[1]==="http:"?80:443))==(ck[3]||(ck[1]==="http:"?80:443)))),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e,f=this.createTween(a,b),g=cQ.exec(b),h=f.cur(),i=+h||0,j=1;if(g){c=+g[2],d=g[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&i){i=p.css(f.elem,a,!0)||c||1;do e=j=j||".5",i=i/j,p.style(f.elem,a,i+d),j=f.cur()/h;while(j!==1&&j!==e)}f.unit=d,f.start=i,f.end=g[1]?i+(g[1]+1)*c:c}return f}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j,k,l,m=this[0],n=m&&m.ownerDocument;if(!n)return;return(e=n.body)===m?p.offset.bodyOffset(m):(d=n.documentElement,p.contains(d,m)?(c=m.getBoundingClientRect(),f=da(n),g=d.clientTop||e.clientTop||0,h=d.clientLeft||e.clientLeft||0,i=f.pageYOffset||d.scrollTop,j=f.pageXOffset||d.scrollLeft,k=c.top+i-g,l=c.left+j-h,{top:k,left:l}):{top:0,left:0})},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-ui-1.8.16.custom.min.js b/feincms/static/feincms/jquery-ui-1.8.16.custom.min.js deleted file mode 100755 index 14c9064f7..000000000 --- a/feincms/static/feincms/jquery-ui-1.8.16.custom.min.js +++ /dev/null @@ -1,791 +0,0 @@ -/*! - * jQuery UI 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.16", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({propAttr:c.fn.prop||c.fn.attr,_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d= -this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this, -"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart": -"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight, -outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a, -"tabindex"),d=isNaN(b);return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&& -a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&& -c.ui.isOverAxis(b,e,i)}})}})(jQuery); -;/*! - * jQuery UI Widget 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Widget - */ -(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)try{b(d).triggerHandler("remove")}catch(e){}k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(d){}});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]= -function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)): -d;if(e&&d.charAt(0)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options= -b.extend(true,{},this.options,this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+ -"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled", -c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery); -;/*! - * jQuery UI Mouse 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Mouse - * - * Depends: - * jquery.ui.widget.js - */ -(function(b){var d=false;b(document).mouseup(function(){d=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+ -this.widgetName)},_mouseDown:function(a){if(!d){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,f=a.which==1,g=typeof this.options.cancel=="string"&&a.target.nodeName?b(a.target).closest(this.options.cancel).length:false;if(!f||g||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted= -this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(e){return c._mouseMove(e)};this._mouseUpDelegate=function(e){return c._mouseUp(e)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return d=true}},_mouseMove:function(a){if(b.browser.msie&& -!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= -false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -;/* - * jQuery UI Position 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Position - */ -(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, -left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= -k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= -m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= -d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= -a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), -g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); -;/* - * jQuery UI Draggable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== -"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= -this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;if(b.iframeFix)d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options; -this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true}, -_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b= -false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, -10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle|| -!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&& -a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!= -"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"), -10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+ -this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&& -!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.left<g[0])e=g[0]+this.offset.click.left; -if(a.pageY-this.offset.click.top<g[1])h=g[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>g[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.top<g[1]||h-this.offset.click.top>g[3])?h:!(h-this.offset.click.top<g[1])?h-b.grid[1]:h+b.grid[1]:h;e=b.grid[0]?this.originalPageX+Math.round((e-this.originalPageX)/ -b.grid[0])*b.grid[0]:this.originalPageX;e=g?!(e-this.offset.click.left<g[0]||e-this.offset.click.left>g[2])?e:!(e-this.offset.click.left<g[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version< -526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b, -c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.16"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var h=d.data(this,"sortable");if(h&&!h.options.disabled){c.sortables.push({instance:h,shouldRevert:h.options.revert}); -h.refreshPositions();h._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval= -false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",true); -this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top; -c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&& -this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity= -a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!= -"x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left< -c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()- -c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this, -width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,h=b.offset.left,g=h+c.helperProportions.width,n=b.offset.top,o=n+c.helperProportions.height,i=c.snapElements.length-1;i>=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e<h&&h<l+e&&k-e<n&&n<m+e||j-e<h&&h<l+e&&k-e<o&&o<m+e||j-e<g&&g<l+e&&k-e<n&&n<m+e||j-e<g&&g<l+e&&k-e<o&& -o<m+e){if(f.snapMode!="inner"){var p=Math.abs(k-o)<=e,q=Math.abs(m-n)<=e,r=Math.abs(j-g)<=e,s=Math.abs(l-h)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l}).left-c.margins.left}var t= -p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(k-n)<=e;q=Math.abs(m-o)<=e;r=Math.abs(j-h)<=e;s=Math.abs(l-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[i].snapping&& -(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=p||q||r||s||t}else{c.snapElements[i].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"), -10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery); -;/* - * jQuery UI Droppable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Droppables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.mouse.js - * jquery.ui.draggable.js - */ -(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this); -a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&& -this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass); -this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g= -d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop", -a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.16"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height; -switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>= -i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!= -"none";if(c[f].visible){e=="mousedown"&&c[f]._activate.call(c[f],b);c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight}}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem|| -a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},dragStart:function(a,b){a.element.parents(":not(body,html)").bind("scroll.droppable",function(){a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)})},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance); -if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})},dragStop:function(a,b){a.element.parents(":not(body,html)").unbind("scroll.droppable"); -a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)}}})(jQuery); -;/* - * jQuery UI Resizable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element, -_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), -top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= -this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", -nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== -String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); -this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); -var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a= -false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"}); -this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff= -{width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis]; -if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false}, -_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f, -{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(b){var a=this.options,c,d,f;a={minWidth:k(a.minWidth)?a.minWidth:0,maxWidth:k(a.maxWidth)?a.maxWidth:Infinity,minHeight:k(a.minHeight)?a.minHeight:0,maxHeight:k(a.maxHeight)?a.maxHeight: -Infinity};if(this._aspectRatio||b){b=a.minHeight*this.aspectRatio;d=a.minWidth/this.aspectRatio;c=a.maxHeight*this.aspectRatio;f=a.maxWidth/this.aspectRatio;if(b>a.minWidth)a.minWidth=b;if(d>a.minHeight)a.minHeight=d;if(c<a.maxWidth)a.maxWidth=c;if(f<a.maxHeight)a.maxHeight=f}this._vBoundaries=a},_updateCache:function(b){this.offset=this.helper.offset();if(k(b.left))this.position.left=b.left;if(k(b.top))this.position.top=b.top;if(k(b.height))this.size.height=b.height;if(k(b.width))this.size.width= -b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(k(b.height))b.width=b.height*this.aspectRatio;else if(k(b.width))b.height=b.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this._vBoundaries,c=this.axis,d=k(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=k(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=k(b.width)&&a.minWidth&& -a.minWidth>b.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&l)b.left=i-a.minWidth;if(d&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left= -null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)|| -0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+ -a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+ -c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]); -b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.16"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(), -10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top- -f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var l=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:l.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(l.css("position"))){c._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType? -e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a= -e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing, -step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement= -e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset; -var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left: -a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top- -d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition, -f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25, -display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b= -e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height= -d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery); -;/* - * jQuery UI Selectable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"), -selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, -c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting", -c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d= -this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting"); -a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&& -!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d= -e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Sortable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Sortables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable"); -this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a=== -"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&& -!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, -left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; -this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!= -document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a); -return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top< -b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()- -b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this, -a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0], -e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset(); -c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): -this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null, -dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")}, -toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers|| -this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection(); -var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)}, -_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith(); -if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), -this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element), -this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&& -this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b= -this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f= -d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")|| -0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out", -a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h- -f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b= -this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width== -""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top= -this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a= -{top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"), -10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"? -document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"), -10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b= -this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&& -this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset(); -var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g- -this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g- -this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0], -this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]= -"";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove", -f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this, -this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop", -a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()}, -_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Accordion 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); -a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); -if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", -function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a= -this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); -this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); -b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); -a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ -c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; -if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); -if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(), -e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight|| -e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false", -"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.16", -animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/); -f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide", -paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); -;/* - * jQuery UI Autocomplete 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.propAttr("readOnly"))){g= -false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!= -a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)}; -this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&& -a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); -d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&& -b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source= -this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close(); -this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label|| -b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this; -d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, -"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery); -(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", --1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); -this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b, -this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[d.fn.prop?"prop":"attr"]("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery); -;/* - * jQuery UI Button 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(b){var h,i,j,g,l=function(){var a=b(this).find(":ui-button");setTimeout(function(){a.button("refresh")},1)},k=function(a){var c=a.name,e=a.form,f=b([]);if(c)f=e?b(e).find("[name='"+c+"']"):b("[name='"+c+"']",a.ownerDocument).filter(function(){return!this.form});return f};b.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",l);if(typeof this.options.disabled!== -"boolean")this.options.disabled=this.element.propAttr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var a=this,c=this.options,e=this.type==="checkbox"||this.type==="radio",f="ui-state-hover"+(!e?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",function(){if(!c.disabled){b(this).addClass("ui-state-hover"); -this===h&&b(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||b(this).removeClass(f)}).bind("click.button",function(d){if(c.disabled){d.preventDefault();d.stopImmediatePropagation()}});this.element.bind("focus.button",function(){a.buttonElement.addClass("ui-state-focus")}).bind("blur.button",function(){a.buttonElement.removeClass("ui-state-focus")});if(e){this.element.bind("change.button",function(){g||a.refresh()});this.buttonElement.bind("mousedown.button",function(d){if(!c.disabled){g= -false;i=d.pageX;j=d.pageY}}).bind("mouseup.button",function(d){if(!c.disabled)if(i!==d.pageX||j!==d.pageY)g=true})}if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled||g)return false;b(this).toggleClass("ui-state-active");a.buttonElement.attr("aria-pressed",a.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled||g)return false;b(this).addClass("ui-state-active");a.buttonElement.attr("aria-pressed","true"); -var d=a.element[0];k(d).not(d).map(function(){return b(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;b(this).addClass("ui-state-active");h=this;b(document).one("mouseup",function(){h=null})}).bind("mouseup.button",function(){if(c.disabled)return false;b(this).removeClass("ui-state-active")}).bind("keydown.button",function(d){if(c.disabled)return false;if(d.keyCode==b.ui.keyCode.SPACE|| -d.keyCode==b.ui.keyCode.ENTER)b(this).addClass("ui-state-active")}).bind("keyup.button",function(){b(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(d){d.keyCode===b.ui.keyCode.SPACE&&b(this).click()})}this._setOption("disabled",c.disabled);this._resetButton()},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type=== -"radio"){var a=this.element.parents().filter(":last"),c="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(c);if(!this.buttonElement.length){a=a.length?a.siblings():this.element.siblings();this.buttonElement=a.filter(c);if(!this.buttonElement.length)this.buttonElement=a.find(c)}this.element.addClass("ui-helper-hidden-accessible");(a=this.element.is(":checked"))&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",a)}else this.buttonElement=this.element}, -widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||this.buttonElement.removeAttr("title"); -b.Widget.prototype.destroy.call(this)},_setOption:function(a,c){b.Widget.prototype._setOption.apply(this,arguments);if(a==="disabled")c?this.element.propAttr("disabled",true):this.element.propAttr("disabled",false);else this._resetButton()},refresh:function(){var a=this.element.is(":disabled");a!==this.options.disabled&&this._setOption("disabled",a);if(this.type==="radio")k(this.element[0]).each(function(){b(this).is(":checked")?b(this).button("widget").addClass("ui-state-active").attr("aria-pressed", -"true"):b(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false")},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var a=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"), -c=b("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(a.empty()).text(),e=this.options.icons,f=e.primary&&e.secondary,d=[];if(e.primary||e.secondary){if(this.options.text)d.push("ui-button-text-icon"+(f?"s":e.primary?"-primary":"-secondary"));e.primary&&a.prepend("<span class='ui-button-icon-primary ui-icon "+e.primary+"'></span>");e.secondary&&a.append("<span class='ui-button-icon-secondary ui-icon "+e.secondary+"'></span>");if(!this.options.text){d.push(f?"ui-button-icons-only": -"ui-button-icon-only");this.hasTitle||a.attr("title",c)}}else d.push("ui-button-text-only");a.addClass(d.join(" "))}}});b.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(a,c){a==="disabled"&&this.buttons.button("option",a,c);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var a=this.element.css("direction")=== -"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(a?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(a?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); -b.Widget.prototype.destroy.call(this)}})})(jQuery); -;/* - * jQuery UI Dialog 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, -position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ -b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&!i.isDefaultPrevented()&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g), -h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id", -e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); -a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!== -b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1; -d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target=== -f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a, -function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('<button type="button"></button>').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", -handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, -originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", -f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): -[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); -if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): -e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= -this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- -b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), -create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&!d.isDefaultPrevented()&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()|| -c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&& -c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+ -"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery); -;/* - * jQuery UI Slider 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var a=this,b=this.options,c=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f=b.values&&b.values.length||1,e=[];this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+ -this.orientation+" ui-widget ui-widget-content ui-corner-all"+(b.disabled?" ui-slider-disabled ui-disabled":""));this.range=d([]);if(b.range){if(b.range===true){if(!b.values)b.values=[this._valueMin(),this._valueMin()];if(b.values.length&&b.values.length!==2)b.values=[b.values[0],b.values[0]]}this.range=d("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j<f;j+=1)e.push("<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>"); -this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", -g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length? -(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i- -m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false; -this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b= -this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b= -this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b); -c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c<f))c=f;if(c!==this.values(b)){f=this.values();f[b]=c;a=this._trigger("slide",a,{handle:this.handles[b],value:c,values:f});this.values(b?0:1);a!==false&&this.values(b,c,true)}}else if(c!==this.value()){a=this._trigger("slide",a,{handle:this.handles[b],value:c}); -a!==false&&this.value(c)}},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value= -this._trimAlignValue(a);this._refreshValue();this._change(null,0)}else return this._value()},values:function(a,b){var c,f,e;if(arguments.length>1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e<c.length;e+=1){c[e]=this._trimAlignValue(f[e]);this._change(null,e)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(a): -this.value();else return this._values()},_setOption:function(a,b){var c,f=0;if(d.isArray(this.options.values))f=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(a){case "disabled":if(b){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.propAttr("disabled",true);this.element.addClass("ui-disabled")}else{this.handles.propAttr("disabled",false);this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation(); -this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<f;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a)},_values:function(a){var b,c;if(arguments.length){b=this.options.values[a]; -return b=this._trimAlignValue(b)}else{b=this.options.values.slice();for(c=0;c<b.length;c+=1)b[c]=this._trimAlignValue(b[c]);return b}},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a= -this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e- -g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"}, -b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Tabs 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& -e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= -d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| -(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); -this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= -this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); -if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); -this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ -g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", -function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; -this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= --1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; -d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= -d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, -e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); -j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); -if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, -this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, -load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, -"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, -url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.16"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&& -a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery); -;/* - * jQuery UI Datepicker 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker - * - * Depends: - * jquery.ui.core.js - */ -(function(d,C){function M(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass= -"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={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:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10", -minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false,disabled:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=N(d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function N(a){return a.bind("mouseout", -function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); -b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.16"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, -setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g, -"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", -function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c== -"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker(): -d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a, -b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+= -1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ -2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b= -d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e= -a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a, -"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f== -a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"? -d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true),i=this._getMinMaxDate(e,"min"),g=this._getMinMaxDate(e,"max");H(e.settings,f);if(i!==null&&f.dateFormat!==C&&f.minDate===C)e.settings.minDate=this._formatDate(e,i);if(g!==null&&f.dateFormat!==C&&f.maxDate===C)e.settings.maxDate=this._formatDate(e,g);this._attachments(d(a),e);this._autoSize(e);this._setDate(e,h);this._updateAlternate(e); -this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl"); -b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv);c[0]&&d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]);if(a=d.datepicker._get(b,"onSelect")){c=d.datepicker._formatDate(b);a.apply(b.input?b.input[0]:null,[c,b])}else d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target, -a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c= -a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b, -"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==C?a.keyCode:a.charCode); -return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input", -a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");c=c?c.apply(a,[a,b]):{};if(c!==false){H(b.settings,c);b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value= -"";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b); -c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing= -true;d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}); -a.dpDiv.find("."+this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&& -!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(), -h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b= -this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b); -this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, -_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"): -0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"? -"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a); -this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField"); -if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"? -b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1<a.length&&a.charAt(A+1)==p)&&A++;return p},m=function(p){var D= -o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"&&D?4:p=="o"?3:2)+"}");p=b.substring(q).match(p);if(!p)throw"Missing number at position "+q;q+=p[0].length;return parseInt(p[0],10)},n=function(p,D,K){p=d.map(o(p)?K:D,function(w,x){return[[x,w]]}).sort(function(w,x){return-(w[1].length-x[1].length)});var E=-1;d.each(p,function(w,x){w=x[1];if(b.substr(q,w.length).toLowerCase()==w.toLowerCase()){E=x[0];q+=w.length;return false}});if(E!=-1)return E+1;else throw"Unknown name at position "+q;},s= -function(){if(b.charAt(q)!=a.charAt(A))throw"Unexpected literal at position "+q;q++},q=0,A=0;A<a.length;A++)if(k)if(a.charAt(A)=="'"&&!o("'"))k=false;else s();else switch(a.charAt(A)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();j=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();j=v.getMonth()+ -1;l=v.getDate();break;case "'":if(o("'"))s();else k=true;break;default:s()}if(q<b.length)throw"Extra/unparsed characters found in date: "+b.substring(q);if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd", -COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames: -null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&a.charAt(k+1)==o)&&k++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},j=function(o,m,n,s){return i(o)?s[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()- -(new Date(b.getFullYear(),0,0)).getTime())/864E5),3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f= -0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+="0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==C?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a); -var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date; -i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g= -Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()> -12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&& -a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay? -new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a)); -n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+B+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m, -g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+B+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&& -a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+B+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,s)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+ -B+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x<i[0];x++){var O= -"";this.maxRows=4;for(var G=0;G<i[1];G++){var P=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",y="";if(l){y+='<div class="ui-datepicker-group';if(i[1]>1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&& -x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var z=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+s[r]+'">'+q[r]+"</span></th>"}y+=z+"</tr></thead><tbody>";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay, -z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q<z;Q++){y+="<tr>";var R=!j?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(r)+"</td>";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&r<k||o&&r>o;R+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(r.getTime()== -P.getTime()&&g==a.selectedMonth&&a._keyEvent||E.getTime()==r.getTime()&&E.getTime()==P.getTime()?" "+this._dayOverClass:"")+(L?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!D?"":" "+I[1]+(r.getTime()==u.getTime()?" "+this._currentClass:"")+(r.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!F||D)&&I[2]?' title="'+I[2]+'"':"")+(L?"":' onclick="DP_jQuery_'+B+".datepicker._selectDay('#"+a.id+"',"+r.getMonth()+","+r.getFullYear()+', this);return false;"')+">"+(F&&!D?" ":L?'<span class="ui-state-default">'+ -r.getDate()+"</span>":'<a class="ui-state-default'+(r.getTime()==b.getTime()?" ui-state-highlight":"")+(r.getTime()==u.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+'" href="#">'+r.getDate()+"</a>")+"</td>";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+"</tr>"}g++;if(g>11){g=0;m++}y+="</tbody></table>"+(l?"</div>"+(i[0]>0&&G==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>': -"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+B+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" >";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&& -(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b, -e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+B+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" >";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+ -(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input? -a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c, -e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a, -"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this; -if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a== -"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.16";window["DP_jQuery_"+B]=d})(jQuery); -;/* - * jQuery UI Progressbar 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); -this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* -this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Effects 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/ - */ -jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], -16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, -a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= -a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", -"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, -0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, -211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, -d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; -f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, -[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b= -0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), -d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement; -if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)}); -return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this, -arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/ -2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b, -d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c, -a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b, -d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g= -0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158; -if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c, -a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery); -;/* - * jQuery UI Effects Blind 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Blind - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","bottom","left","right"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a, -g);b.effects.removeWrapper(a);c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Bounce 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Bounce - * - * Depends: - * jquery.effects.core.js - */ -(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","bottom","left","right"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/ -3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a); -b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery); -;/* - * jQuery UI Effects Clip 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Clip - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","bottom","left","right","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position, -c/2)}var h={};h[g.size]=f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Drop 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Drop - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e== -"show"?1:0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Explode 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Explode - * - * Depends: - * jquery.effects.core.js - */ -(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f= -0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ -e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); -;/* - * jQuery UI Effects Fade 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Fold 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], -10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Highlight 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& -this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Pulsate 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration, -a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery); -;/* - * jQuery UI Effects Scale 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Scale - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a, -b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity= -1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","bottom","left","right","width","height","overflow","opacity"],g=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"], -p=c.effects.setMode(a,b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}}; -if(m=="box"||m=="both"){if(d.from.y!=d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a); -a.css("overflow","hidden").css(a.from);if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from); -child.to=c.effects.setTransition(child,f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a, -n?e:g);c.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Shake 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Shake - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","bottom","left","right"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]= -(h=="pos"?"-=":"+=")+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery); -;/* - * jQuery UI Effects Slide 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Slide - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e); -var i={};i[g]=(f=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Transfer 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Transfer - * - * Depends: - * jquery.effects.core.js - */ -(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); -b.dequeue()})})}})(jQuery); -; \ No newline at end of file diff --git a/feincms/static/feincms/jquery-ui-1.8.22.custom.min.js b/feincms/static/feincms/jquery-ui-1.8.22.custom.min.js new file mode 100755 index 000000000..e36a7f0f6 --- /dev/null +++ b/feincms/static/feincms/jquery-ui-1.8.22.custom.min.js @@ -0,0 +1,125 @@ +/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.core.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.22",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.widget.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.mouse.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.position.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.draggable.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){return d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.22"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g=b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensitivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.push({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{start:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!e.length)return;var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.droppable.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);return this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable"),this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;return this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance))return e=!0,!1}),e?!1:this.accept.call(this.element[0],d.currentItem||d.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d)),this.element):!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.22"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.left,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h<d.length;h++){if(d[h].options.disabled||b&&!d[h].accept.call(d[h].element[0],b.currentItem||b.element))continue;for(var i=0;i<f.length;i++)if(f[i]==d[h].element[0]){d[h].proportions.height=0;continue g}d[h].visible=d[h].element.css("display")!="none";if(!d[h].visible)continue;e=="mousedown"&&d[h]._activate.call(d[h],c),d[h].offset=d[h].element.offset(),d[h].proportions={width:d[h].element[0].offsetWidth,height:d[h].element[0].offsetHeight}}},drop:function(b,c){var d=!1;return a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c))}),d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.resizable.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;return d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width)),a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=this.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(!a.browser.msie||!a(c).is(":hidden")&&!a(c).parents(":hidden").length)e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0});else continue}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.22"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.selectable.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}),!1},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;return a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove(),!1}}),a.extend(a.ui.selectable,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.sortable.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=this.options.axis==="x"||a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=this.options.axis==="y"||a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();return e?this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1):!1},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f&&this.ready)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i],this.direction=j-h>0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._uiHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.accordion.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}return f?(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),!1):!0},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];return this._clickHandler({target:b},b),this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(d.disabled)return;if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!g)return;return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(this.running)return;this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data)}}),a.extend(a.ui.accordion,{version:"1.8.22",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size()){b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);return}if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.autocomplete.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.isMultiLine=this.element.is("textarea"),this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(b.options.disabled||b.element.propAttr("readOnly"))return;d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._keyEvent("previous",c);break;case e.DOWN:b._keyEvent("next",c);break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){if(b.options.disabled)return;b.selectedItem=null,b.previous=b.element.val()}).bind("blur.autocomplete",function(a){if(b.options.disabled)return;clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150)}),this._initSource(),this.menu=a("<ul></ul>").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,c,d;a.isArray(this.options.source)?(c=this.options.source,this.source=function(b,d){d(a.ui.autocomplete.filter(c,b.term))}):typeof this.options.source=="string"?(d=this.options.source,this.source=function(c,e){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:d,data:c,dataType:"json",success:function(a,b){e(a)},error:function(){e([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)===!1)return;return this._search(a)},_search:function(a){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.source({term:a},this._response())},_response:function(){var a=this,b=++c;return function(d){b===c&&a.__response(d),a.pending--,a.pending||a.element.removeClass("ui-autocomplete-loading")}},__response:function(a){!this.options.disabled&&a&&a.length?(a=this._normalize(a),this._suggest(a),this._trigger("open")):this.close()},close:function(a){clearTimeout(this.closing),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.deactivate(),this._trigger("close",a))},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(b){return b.length&&b[0].label&&b[0].value?b:a.map(b,function(b){return typeof b=="string"?{label:b,value:b}:a.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(b){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(c,b),this.menu.deactivate(),this.menu.refresh(),c.show(),this._resizeMenu(),c.position(a.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(new a.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(b,c){var d=this;a.each(c,function(a,c){d._renderItem(b,c)})},_renderItem:function(b,c){return a("<li></li>").data("item.autocomplete",c).append(a("<a></a>").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)},widget:function(){return this.menu.element},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})})(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(!a(c.target).closest(".ui-menu-item a").length)return;c.preventDefault(),b.select(c)}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){if(!this.active)return;this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active){this.activate(c,this.element.children(b));return}var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:first")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[a.fn.prop?"prop":"attr"]("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})}(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.button.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);return c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form})),e};a.widget("ui.button",{options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",j),typeof this.options.disabled!="boolean"?this.options.disabled=!!this.element.propAttr("disabled"):this.element.propAttr("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var b=this,h=this.options,i=this.type==="checkbox"||this.type==="radio",l="ui-state-hover"+(i?"":" ui-state-active"),m="ui-state-focus";h.label===null&&(h.label=this.buttonElement.html()),this.buttonElement.addClass(g).attr("role","button").bind("mouseenter.button",function(){if(h.disabled)return;a(this).addClass("ui-state-hover"),this===c&&a(this).addClass("ui-state-active")}).bind("mouseleave.button",function(){if(h.disabled)return;a(this).removeClass(l)}).bind("click.button",function(a){h.disabled&&(a.preventDefault(),a.stopImmediatePropagation())}),this.element.bind("focus.button",function(){b.buttonElement.addClass(m)}).bind("blur.button",function(){b.buttonElement.removeClass(m)}),i&&(this.element.bind("change.button",function(){if(f)return;b.refresh()}),this.buttonElement.bind("mousedown.button",function(a){if(h.disabled)return;f=!1,d=a.pageX,e=a.pageY}).bind("mouseup.button",function(a){if(h.disabled)return;if(d!==a.pageX||e!==a.pageY)f=!0})),this.type==="checkbox"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).toggleClass("ui-state-active"),b.buttonElement.attr("aria-pressed",b.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).addClass("ui-state-active"),b.buttonElement.attr("aria-pressed","true");var c=b.element[0];k(c).not(c).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown.button",function(){if(h.disabled)return!1;a(this).addClass("ui-state-active"),c=this,a(document).one("mouseup",function(){c=null})}).bind("mouseup.button",function(){if(h.disabled)return!1;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(b){if(h.disabled)return!1;(b.keyCode==a.ui.keyCode.SPACE||b.keyCode==a.ui.keyCode.ENTER)&&a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(b){b.keyCode===a.ui.keyCode.SPACE&&a(this).click()})),this._setOption("disabled",h.disabled),this._resetButton()},_determineButtonType:function(){this.element.is(":checkbox")?this.type="checkbox":this.element.is(":radio")?this.type="radio":this.element.is("input")?this.type="input":this.type="button";if(this.type==="checkbox"||this.type==="radio"){var a=this.element.parents().filter(":last"),b="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(b),this.buttonElement.length||(a=a.length?a.siblings():this.element.siblings(),this.buttonElement=a.filter(b),this.buttonElement.length||(this.buttonElement=a.find(b))),this.element.addClass("ui-helper-hidden-accessible");var c=this.element.is(":checked");c&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.attr("aria-pressed",c)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(g+" "+h+" "+i).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title"),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled"){c?this.element.propAttr("disabled",!0):this.element.propAttr("disabled",!1);return}this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b),this.type==="radio"?k(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input"){this.options.label&&this.element.val(this.options.label);return}var b=this.buttonElement.removeClass(i),c=a("<span></span>",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>"),d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>"),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.dialog.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},f=a.attrFn||{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0,click:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("<div></div>")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("<span></span>")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("<span></span>").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=a("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('<button type="button"></button>').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(g);a.each(d,function(a,b){if(a==="click")return;a in f?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||" "))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.22",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()<a.ui.dialog.overlay.maxZ)return!1})},1),a(document).bind("keydown.dialog-overlay",function(c){b.options.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}),a(window).bind("resize.dialog-overlay",a.ui.dialog.overlay.resize));var c=(this.oldInstances.pop()||a("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b<c?a(window).height()+"px":b+"px"):a(document).height()+"px"},width:function(){var b,c;return a.browser.msie?(b=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),c=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth),b<c?a(window).width()+"px":b+"px"):a(document).width()+"px"},resize:function(){var b=a([]);a.each(a.ui.dialog.overlay.instances,function(){b=b.add(this)}),b.css({width:0,height:0}).css({width:a.ui.dialog.overlay.width(),height:a.ui.dialog.overlay.height()})}}),a.extend(a.ui.dialog.overlay.prototype,{destroy:function(){a.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.slider.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.tabs.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1<this.anchors.length?1:-1)),c.disabled=a.map(a.grep(c.disabled,function(a,c){return a!=b}),function(a,c){return a>=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.22"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a<c.anchors.length?a:0)},a),b&&b.stopPropagation()}),f=c._unrotate||(c._unrotate=b?function(a){e()}:function(a){a.clientX&&c.rotate(null)});return a?(this.element.bind("tabsshow",e),this.anchors.bind(d.event+".tabs",f),e()):(clearTimeout(c.rotation),this.element.unbind("tabsshow",e),this.anchors.unbind(d.event+".tabs",f),delete this._rotate,delete this._unrotate),this}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.datepicker.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={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:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);if(!c.length)return;c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);if($.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])||!d.length)return;d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover")})}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}$.extend($.ui,{datepicker:{version:"1.8.22"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){return extendRemove(this._defaults,a||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);if(c.hasClass(this.markerClassName))return;this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a)},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]),!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);if(c.hasClass(this.markerClassName))return;c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block")},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f),this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);return c&&!c.inline&&this._setDateFromField(c,b),c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(d){$.datepicker.log(d)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if($.datepicker._isDisabledDatepicker(a)||$.datepicker._lastInput==a)return;var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){return e|=$(this).css("position")=="fixed",!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a)),this._attachHandlers(a);var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+(c?0:$(document).scrollLeft()),i=document.documentElement.clientHeight+(c?0:$(document).scrollTop());return b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0),b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!b||a&&b!=$.data(a,PROP_NAME))return;if(this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=function(){$.datepicker._tidyDialog(b)};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,e):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,e),c||e(),this._datepickerShowing=!1;var f=this._get(b,"onClose");f&&f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!$.datepicker._curInst)return;var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);if(this._isDisabledDatepicker(d[0]))return;this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e)},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if($(d).hasClass(this._unselectableClass)||this._isDisabledDatepicker(e[0]))return;var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;return c&&s++,c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;return r+=f[0].length,parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase())return f=c[0],r+=d.length,!1});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;do{var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}while(!0)}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;return c&&m++,c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;return c&&e++,c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()==a.lastVal)return;var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;return b.setDate(b.getDate()+a),b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());return f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0)),this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){return a?(a.setHours(a.getHours()>12?a.getHours()+2:0),a):null},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_attachHandlers:function(a){var b=this._get(a,"stepMonths"),c="#"+a.id;a.dpDiv.find("[data-handler]").map(function(){var a={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,-b,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,+b,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(c)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(c,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),a[this.getAttribute("data-handler")])})},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click">'+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' data-handler="selectDay" data-event="click" data-month="'+Y.getMonth()+'" data-year="'+Y.getFullYear()+'"')+">"+(bb&&!G?" ":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="</div>",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;return e=d&&e>d?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.22",window["DP_jQuery_"+dpuuid]=$})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.ui.progressbar.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.core.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +jQuery.effects||function(a,b){function c(b){var c;return b&&b.constructor==Array&&b.length==3?b:(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))?[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)]:(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))?[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))?[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)]:(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))?[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)]:(c=/rgba\(0, 0, 0, 0\)/.exec(b))?e.transparent:e[a.trim(b).toLowerCase()]}function d(b,d){var e;do{e=(a.curCSS||a.css)(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};return a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete,[b,c,d,e]}function l(b){return!b||typeof b=="number"||a.fx.speeds[b]?!0:typeof b=="string"&&!a.effects[b]?!0:!1}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){return a.isFunction(d)&&(e=d,d=null),this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class")||"";a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.22",save:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.data("ec.storage."+b[c],a[0].style[b[c]])},restore:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.css(b[c],a.data("ec.storage."+b[c]))},setMode:function(a,b){return b=="toggle"&&(b=a.is(":hidden")?"show":"hide"),b},getBaseline:function(a,b){var c,d;switch(a[0]){case"top":c=0;break;case"middle":c=.5;break;case"bottom":c=1;break;default:c=a[0]/b.height}switch(a[1]){case"left":d=0;break;case"center":d=.5;break;case"right":d=1;break;default:d=a[1]/b.width}return{x:d,y:c}},createWrapper:function(b){if(b.parent().is(".ui-effects-wrapper"))return b.parent();var c={width:b.outerWidth(!0),height:b.outerHeight(!0),"float":b.css("float")},d=a("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}}),a.easing.jswing=a.easing.swing,a.extend(a.easing,{def:"easeOutQuad",swing:function(b,c,d,e,f){return a.easing[a.easing.def](b,c,d,e,f)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b+c:d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b+c:-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b*b+c:d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return b==0?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){return b==0?c:b==e?c+d:(b/=e/2)<1?d/2*Math.pow(2,10*(b-1))+c:d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){return(b/=e/2)<1?-d/2*(Math.sqrt(1-b*b)-1)+c:d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(b==0)return c;if((b/=e)==1)return c+d;g||(g=e*.3);if(h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g))+c},easeOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(b==0)return c;if((b/=e)==1)return c+d;g||(g=e*.3);if(h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*b)*Math.sin((b*e-f)*2*Math.PI/g)+d+c},easeInOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(b==0)return c;if((b/=e/2)==2)return c+d;g||(g=e*.3*1.5);if(h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return b<1?-0.5*h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g)+c:h*Math.pow(2,-10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g)*.5+d+c},easeInBack:function(a,c,d,e,f,g){return g==b&&(g=1.70158),e*(c/=f)*c*((g+1)*c-g)+d},easeOutBack:function(a,c,d,e,f,g){return g==b&&(g=1.70158),e*((c=c/f-1)*c*((g+1)*c+g)+1)+d},easeInOutBack:function(a,c,d,e,f,g){return g==b&&(g=1.70158),(c/=f/2)<1?e/2*c*c*(((g*=1.525)+1)*c-g)+d:e/2*((c-=2)*c*(((g*=1.525)+1)*c+g)+2)+d},easeInBounce:function(b,c,d,e,f){return e-a.easing.easeOutBounce(b,f-c,0,e,f)+d},easeOutBounce:function(a,b,c,d,e){return(b/=e)<1/2.75?d*7.5625*b*b+c:b<2/2.75?d*(7.5625*(b-=1.5/2.75)*b+.75)+c:b<2.5/2.75?d*(7.5625*(b-=2.25/2.75)*b+.9375)+c:d*(7.5625*(b-=2.625/2.75)*b+.984375)+c},easeInOutBounce:function(b,c,d,e,f){return c<f/2?a.easing.easeInBounce(b,c*2,0,e,f)*.5+d:a.easing.easeOutBounce(b,c*2-f,0,e,f)*.5+e*.5+d}})}(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.blind.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.bounce.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight(!0)/3:c.outerWidth(!0)/3);e=="show"&&c.css("opacity",0).css(j,k=="pos"?-g:g),e=="hide"&&(g=g/(h*2)),e!="hide"&&h--;if(e=="show"){var l={opacity:1};l[j]=(k=="pos"?"+=":"-=")+g,c.animate(l,i/2,b.options.easing),g=g/2,h--}for(var m=0;m<h;m++){var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing),g=e=="hide"?g*2:g/2}if(e=="hide"){var l={opacity:0};l[j]=(k=="pos"?"-=":"+=")+g,c.animate(l,i/2,b.options.easing,function(){c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}else{var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.clip.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.clip=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","height","width"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=c[0].tagName=="IMG"?g:c,i={size:f=="vertical"?"height":"width",position:f=="vertical"?"top":"left"},j=f=="vertical"?h.height():h.width();e=="show"&&(h.css(i.size,0),h.css(i.position,j/2));var k={};k[i.size]=e=="show"?j:0,k[i.position]=e=="show"?0:j/2,h.animate(k,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.drop.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.drop=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","opacity"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0)/2:c.outerWidth(!0)/2);e=="show"&&c.css("opacity",0).css(g,h=="pos"?-i:i);var j={opacity:e=="show"?1:0};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.explode.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.explode=function(b){return this.queue(function(){var c=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3,d=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?a(this).is(":visible")?"hide":"show":b.options.mode;var e=a(this).show().css("visibility","hidden"),f=e.offset();f.top-=parseInt(e.css("marginTop"),10)||0,f.left-=parseInt(e.css("marginLeft"),10)||0;var g=e.outerWidth(!0),h=e.outerHeight(!0);for(var i=0;i<c;i++)for(var j=0;j<d;j++)e.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.fade.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.fold.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.highlight.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.pulsate.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i<e;i++)c.animate({opacity:h},f,b.options.easing),h=(h+1)%2;c.animate({opacity:h},f,b.options.easing,function(){h==0&&c.hide(),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}).dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.scale.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.puff=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide"),e=parseInt(b.options.percent,10)||150,f=e/100,g={height:c.height(),width:c.width()};a.extend(b.options,{fade:!0,mode:d,percent:d=="hide"?e:100,from:d=="hide"?g:{height:g.height*f,width:g.width*f}}),c.effect("scale",b.options,b.duration,b.callback),c.dequeue()})},a.effects.scale=function(b){return this.queue(function(){var c=a(this),d=a.extend(!0,{},b.options),e=a.effects.setMode(c,b.options.mode||"effect"),f=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:e=="hide"?0:100),g=b.options.direction||"both",h=b.options.origin;e!="effect"&&(d.origin=h||["middle","center"],d.restore=!0);var i={height:c.height(),width:c.width()};c.from=b.options.from||(e=="show"?{height:0,width:0}:i);var j={y:g!="horizontal"?f/100:1,x:g!="vertical"?f/100:1};c.to={height:i.height*j.y,width:i.width*j.x},b.options.fade&&(e=="show"&&(c.from.opacity=0,c.to.opacity=1),e=="hide"&&(c.from.opacity=1,c.to.opacity=0)),d.from=c.from,d.to=c.to,d.mode=e,c.effect("size",d,b.duration,b.callback),c.dequeue()})},a.effects.size=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","width","height","overflow","opacity"],e=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],g=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],i=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],j=a.effects.setMode(c,b.options.mode||"effect"),k=b.options.restore||!1,l=b.options.scale||"both",m=b.options.origin,n={height:c.height(),width:c.width()};c.from=b.options.from||n,c.to=b.options.to||n;if(m){var p=a.effects.getBaseline(m,n);c.from.top=(n.height-c.from.height)*p.y,c.from.left=(n.width-c.from.width)*p.x,c.to.top=(n.height-c.to.height)*p.y,c.to.left=(n.width-c.to.width)*p.x}var q={from:{y:c.from.height/n.height,x:c.from.width/n.width},to:{y:c.to.height/n.height,x:c.to.width/n.width}};if(l=="box"||l=="both")q.from.y!=q.to.y&&(d=d.concat(h),c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(d=d.concat(i),c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to));(l=="content"||l=="both")&&q.from.y!=q.to.y&&(d=d.concat(g),c.from=a.effects.setTransition(c,g,q.from.y,c.from),c.to=a.effects.setTransition(c,g,q.to.y,c.to)),a.effects.save(c,k?d:e),c.show(),a.effects.createWrapper(c),c.css("overflow","hidden").css(c.from);if(l=="content"||l=="both")h=h.concat(["marginTop","marginBottom"]).concat(g),i=i.concat(["marginLeft","marginRight"]),f=d.concat(h).concat(i),c.find("*[width]").each(function(){var c=a(this);k&&a.effects.save(c,f);var d={height:c.height(),width:c.width()};c.from={height:d.height*q.from.y,width:d.width*q.from.x},c.to={height:d.height*q.to.y,width:d.width*q.to.x},q.from.y!=q.to.y&&(c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to)),c.css(c.from),c.animate(c.to,b.duration,b.options.easing,function(){k&&a.effects.restore(c,f)})});c.animate(c.to,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){c.to.opacity===0&&c.css("opacity",c.from.opacity),j=="hide"&&c.hide(),a.effects.restore(c,k?d:e),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.shake.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.shake=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"left",g=b.options.distance||20,h=b.options.times||3,i=b.duration||b.options.duration||140;a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",l={},m={},n={};l[j]=(k=="pos"?"-=":"+=")+g,m[j]=(k=="pos"?"+=":"-=")+g*2,n[j]=(k=="pos"?"-=":"+=")+g*2,c.animate(l,i,b.options.easing);for(var p=1;p<h;p++)c.animate(m,i,b.options.easing).animate(n,i,b.options.easing);c.animate(m,i,b.options.easing).animate(l,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.slide.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.slide=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"show"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c).css({overflow:"hidden"});var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0):c.outerWidth(!0));e=="show"&&c.css(g,h=="pos"?isNaN(i)?"-"+i:-i:i);var j={};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 +* https://github.com/jquery/jquery-ui +* Includes: jquery.effects.transfer.js +* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ +(function(a,b){a.effects.transfer=function(b){return this.queue(function(){var c=a(this),d=a(b.options.to),e=d.offset(),f={top:e.top,left:e.left,height:d.innerHeight(),width:d.innerWidth()},g=c.offset(),h=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);; \ No newline at end of file diff --git a/feincms/templates/admin/feincms/fe_editor.html b/feincms/templates/admin/feincms/fe_editor.html index 62d40a3b0..e6c9e5238 100644 --- a/feincms/templates/admin/feincms/fe_editor.html +++ b/feincms/templates/admin/feincms/fe_editor.html @@ -3,8 +3,8 @@ {% block extrahead %}{{ block.super }} -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.7.1.min.js"></script> -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.16.custom.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery.alerts.js"></script> <script type="text/javascript"> var feincms = { diff --git a/feincms/templates/admin/feincms/fe_editor_done.html b/feincms/templates/admin/feincms/fe_editor_done.html index 72111c535..36f45eb99 100644 --- a/feincms/templates/admin/feincms/fe_editor_done.html +++ b/feincms/templates/admin/feincms/fe_editor_done.html @@ -1,5 +1,5 @@ -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.7.1.min.js"></script> -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.16.custom.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> <script type="text/javascript"> var feincms = { {% if FEINCMS_JQUERY_NO_CONFLICT %} diff --git a/feincms/templates/admin/feincms/fe_tools.html b/feincms/templates/admin/feincms/fe_tools.html index 16abea9b7..cc3a941bb 100644 --- a/feincms/templates/admin/feincms/fe_tools.html +++ b/feincms/templates/admin/feincms/fe_tools.html @@ -5,7 +5,7 @@ (function () { // load jQuery if not yet present if (typeof(feincms) == "undefined") { - var jquery_url = "{{ STATIC_URL }}feincms/jquery-1.7.1.min.js"; + var jquery_url = "{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"; document.write(unescape('%3Cscript src="' + jquery_url + '" type="text/javascript"%3E%3C/script%3E')); } })(); diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index e0ac8fe5b..c3743bd64 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -3,8 +3,8 @@ {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.7.1.min.js"></script> -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.16.custom.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> {% endblock %} <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}feincms/style.css" /> diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index 129f0c146..c2c6c96b8 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -6,8 +6,8 @@ <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}feincms/style.css" /> <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}feincms/fein_tree.css" /> -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.7.1.min.js"></script> -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.16.custom.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> <script type="text/javascript"> var feincms = { {% if FEINCMS_JQUERY_NO_CONFLICT %} From fae004110d07298a73638bcc85bce1bb0d38999a Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 5 Oct 2012 10:08:30 +0200 Subject: [PATCH 0540/1590] Correct docs, register_extensions needs full path now --- docs/integration.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/integration.rst b/docs/integration.rst index 7cadf6b9f..88dd39d1d 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -398,10 +398,10 @@ need them. All of these must be specified in the ``APPLICATIONS`` argument to Letting 3rd party apps define navigation entries ------------------------------------------------ -Short answer: You need the ``navigation`` extension module. Activate it like -this:: +Short answer: You need the ``feincms.module.page.extensions.navigation`` +extension module. Activate it like this:: - Page.register_extensions('navigation') + Page.register_extensions('feincms.module.page.extensions.navigation') Please note however, that this call needs to come after all From f8b6b083f6f123bca1ab4fbdb0e67a14daadb6c6 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 5 Oct 2012 11:10:05 +0200 Subject: [PATCH 0541/1590] Add logging of exceptions to page template tags --- .../module/page/templatetags/feincms_page_tags.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index bd2b7027b..093c1cf17 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -2,19 +2,21 @@ # coding=utf-8 # ------------------------------------------------------------------------ +import logging import warnings from django import template from django.conf import settings -from django.db.models import Q from django.http import HttpRequest -from feincms.module.page.models import Page, PageManager +from feincms.module.page.models import Page from feincms.utils.templatetags import * from feincms.utils.templatetags import _parse_args -register = template.Library() +# ------------------------------------------------------------------------ +logger = logging.getLogger('feincms.templatetags.page') +register = template.Library() # ------------------------------------------------------------------------ @register.assignment_tag(takes_context=True) @@ -436,6 +438,7 @@ def siblings_along_path_to(page_list, page2): {% endwith %} """ + if page_list: try: # Try to avoid hitting the database: If the current page is in_navigation, @@ -461,8 +464,8 @@ def siblings_along_path_to(page_list, page2): a_page.level == top_level or any((_is_sibling_of(a_page, a) for a in ancestors))] return siblings - except (AttributeError, ValueError): - pass + except (AttributeError, ValueError), e: + logger.warn("siblings_along_path_to caught exception '%s'", e) return () From 923385d09bd3742704b08f8900b49643ea9742c3 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 5 Oct 2012 11:10:33 +0200 Subject: [PATCH 0542/1590] Add some more docs to navigation extension. --- docs/integration.rst | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/integration.rst b/docs/integration.rst index 88dd39d1d..ad3b48d3a 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -407,8 +407,9 @@ extension module. Activate it like this:: Please note however, that this call needs to come after all ``NavigationExtension`` subclasses have been processed, because otherwise they will not be available for selection in the page administration! (Yes, this is -lame and yes, this is going to change as soon as I find the time to whip up a -better solution.) +lame and yes, this is going to change as soon as we find a +better solution. In the meantime, stick your subclass definition before +the register_extensions call.) Because the use cases for extended navigations are so different, FeinCMS does not go to great lengths trying to cover them all. What it does though @@ -446,4 +447,22 @@ You don't need to do anything else as long as you use the built-in for p in page.children.in_navigation(): yield p - Page.register_extensions('navigation') + Page.register_extensions('feincms.module.page.extensions.navigation') + +Note that the objects returned should at least try to mimic a real page so +navigation template tags as ``siblings_along_path_to`` and friends continue +to work, ie. at least the following attributes should exist: + +:: + + title = '(whatever)' + url = '(whatever)' + + # Attributes that MPTT assumes to exist + parent_id = page.id + tree_id = page.tree_id + level = page.level+1 + lft = page.lft + rght = page.rght + + From 918ecebf04e1f4f2b93912e8ac9ea99303793eb4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 3 Oct 2012 12:01:05 +0200 Subject: [PATCH 0543/1590] Flush the page cache after a delete() too --- feincms/module/page/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 8ed335b7b..b0bf50b12 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -271,6 +271,13 @@ def save(self, *args, **kwargs): super(Page, page).save() # do not recurse save.alters_data = True + @commit_on_success + def delete(self, *args, **kwargs): + super(Page, self).delete(*args, **kwargs) + ck = self.path_to_cache_key(self._original_cached_url) + django_cache.delete(ck) + delete.alters_data = True + @models.permalink def get_absolute_url(self): """ From a05b55cef292c98d8238a54ff963fabbcb3d6257 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 5 Oct 2012 15:33:17 +0200 Subject: [PATCH 0544/1590] Correct bug that would wrongly suppress entries in feincms_nav when using navigation extension. --- .../page/templatetags/feincms_page_tags.py | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 093c1cf17..eafb0d676 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -99,26 +99,23 @@ def _filter(iterable): if hasattr(feincms_page, 'navigation_extension'): # Filter out children of nodes which have a navigation extension - extended_node_rght = [] # mptt node right value def _filter(iterable): + current_navextension = (0, 0) for elem in iterable: + # print "ELEM", elem, elem.tree_id, elem.lft, elem.rght elem_right = getattr(elem, mptt_opts.right_attr) + elem_tree = getattr(elem, mptt_opts.tree_id_attr) - if extended_node_rght: - if elem_right < extended_node_rght[-1]: - # Still inside some navigation extension - continue - else: - extended_node_rght.pop() + # Eliminate all subitems of last processed nav extension + if elem_tree == current_navextension[0] and elem_right < current_navextension[1]: + continue + yield elem if getattr(elem, 'navigation_extension', None): - yield elem - extended_node_rght.append(elem_right) - - for extended in elem.extended_navigation(depth=depth, - request=context.get('request')): + current_navextension = (elem_tree, elem_right) + for extended in elem.extended_navigation(depth=depth, request=context.get('request')): # Only return items from the extended navigation which # are inside the requested level+depth values. The # "-1" accounts for the differences in MPTT and @@ -127,9 +124,6 @@ def _filter(iterable): if this_level < level + depth - 1: yield extended - else: - yield elem - queryset = _filter(queryset) # Return a list, not a generator so that it can be consumed From 85482ffc7cb9082cf2bacbbdec5b0ab7ce32bf7c Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Sat, 6 Oct 2012 09:41:41 +0200 Subject: [PATCH 0545/1590] Improve previous: Use MPTT utility method instead of rolling our own. Also catch and log exceptions in nav extension. --- .../page/templatetags/feincms_page_tags.py | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index eafb0d676..bf762f13b 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -89,42 +89,42 @@ def feincms_nav(context, feincms_page, level=1, depth=1): # Subset filtering; allow children of parent as well parents.add(parent.id) - def _filter(iterable): + def _parentactive_filter(iterable): for elem in iterable: if elem.parent_id in parents: yield elem parents.add(elem.id) - queryset = _filter(queryset) + queryset = _parentactive_filter(queryset) if hasattr(feincms_page, 'navigation_extension'): # Filter out children of nodes which have a navigation extension - - def _filter(iterable): - current_navextension = (0, 0) + def _navext_filter(iterable): + current_navextension_node = None for elem in iterable: - # print "ELEM", elem, elem.tree_id, elem.lft, elem.rght - elem_right = getattr(elem, mptt_opts.right_attr) - elem_tree = getattr(elem, mptt_opts.tree_id_attr) - # Eliminate all subitems of last processed nav extension - if elem_tree == current_navextension[0] and elem_right < current_navextension[1]: + if current_navextension_node is not None and \ + current_navextension_node.is_ancestor_of(elem): continue yield elem if getattr(elem, 'navigation_extension', None): - current_navextension = (elem_tree, elem_right) - - for extended in elem.extended_navigation(depth=depth, request=context.get('request')): - # Only return items from the extended navigation which - # are inside the requested level+depth values. The - # "-1" accounts for the differences in MPTT and - # navigation level counting - this_level = getattr(extended, mptt_opts.level_attr, 0) - if this_level < level + depth - 1: - yield extended - - queryset = _filter(queryset) + current_navextension_node = elem + try: + for extended in elem.extended_navigation(depth=depth, request=context.get('request')): + # Only return items from the extended navigation which + # are inside the requested level+depth values. The + # "-1" accounts for the differences in MPTT and + # navigation level counting + this_level = getattr(extended, mptt_opts.level_attr, 0) + if this_level < level + depth - 1: + yield extended + except Exception, e: + logger.warn("feincms_nav caught exception in navigation extension for page %d '%s'", current_navextension_node.id, e) + else: + current_navextension_node = None + + queryset = _navext_filter(queryset) # Return a list, not a generator so that it can be consumed # several times in a template. From 8905f62e3e4880fb815da297a44e690bbe7b0bbc Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Sat, 6 Oct 2012 10:10:20 +0200 Subject: [PATCH 0546/1590] Include traceback information in exceptions logged --- .../module/page/templatetags/feincms_page_tags.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index bf762f13b..4689d5b06 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -3,6 +3,8 @@ # ------------------------------------------------------------------------ import logging +import sys +import traceback import warnings from django import template @@ -18,6 +20,12 @@ register = template.Library() +# ------------------------------------------------------------------------ +# TODO: Belongs in some utility module +def format_exception(e): + top = traceback.extract_tb(sys.exc_info()[2])[-1] + return u"'%s' in %s line %d" % (e, top[0], top[1]) + # ------------------------------------------------------------------------ @register.assignment_tag(takes_context=True) def feincms_nav(context, feincms_page, level=1, depth=1): @@ -120,7 +128,7 @@ def _navext_filter(iterable): if this_level < level + depth - 1: yield extended except Exception, e: - logger.warn("feincms_nav caught exception in navigation extension for page %d '%s'", current_navextension_node.id, e) + logger.warn("feincms_nav caught exception in navigation extension for page %d: %s", current_navextension_node.id, format_exception(e)) else: current_navextension_node = None @@ -459,7 +467,7 @@ def siblings_along_path_to(page_list, page2): any((_is_sibling_of(a_page, a) for a in ancestors))] return siblings except (AttributeError, ValueError), e: - logger.warn("siblings_along_path_to caught exception '%s'", e) + logger.warn("siblings_along_path_to caught exception: %s", format_exception(e)) return () From 1f20ba520119573facf21810aa5f567eeea0baf9 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Tue, 9 Oct 2012 14:35:18 +0200 Subject: [PATCH 0547/1590] Invalidate url-to-page cache when the ct_tracker updates the page. Should fix issue #347 --- feincms/module/extensions/ct_tracker.py | 6 ++++-- feincms/module/page/models.py | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 870607194..6628f0b13 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -59,8 +59,10 @@ def _fetch_content_type_counts(self): super(TrackerContentProxy, self)._fetch_content_type_counts() self.item._ct_inventory = self._to_inventory(self._cache['counts']) - self.item.__class__.objects.filter(id=self.item.id).update( - _ct_inventory=self.item._ct_inventory) + + this_page = self.item.__class__.objects.filter(id=self.item.id) + this_page.update(_ct_inventory=self.item._ct_inventory) + this_page[0].invalidate_cache() # Run post save handler by hand if hasattr(self.item, 'get_descendants'): diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index b0bf50b12..02cd09161 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -245,9 +245,8 @@ def save(self, *args, **kwargs): cached_page_urls[self.id] = self._cached_url super(Page, self).save(*args, **kwargs) - # Okay, we changed the URL -- remove the old stale entry from the cache - ck = self.path_to_cache_key(self._original_cached_url) - django_cache.delete(ck) + # Okay, we have changed the page -- remove the old stale entry from the cache + self.invalidate_cache() # If our cached URL changed we need to update all descendants to # reflect the changes. Since this is a very expensive operation @@ -274,9 +273,13 @@ def save(self, *args, **kwargs): @commit_on_success def delete(self, *args, **kwargs): super(Page, self).delete(*args, **kwargs) + self.invalidate_cache() + delete.alters_data = True + + # Remove the page from the url-to-page cache + def invalidate_cache(self): ck = self.path_to_cache_key(self._original_cached_url) django_cache.delete(ck) - delete.alters_data = True @models.permalink def get_absolute_url(self): From 8f251be5acfaee06b2efa8fe4c3fc4cc8d47c6d9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 10 Oct 2012 18:00:23 +0200 Subject: [PATCH 0548/1590] Revert "Support nested ContentObjectMixin processing" This reverts commit 7c5374a6eb325364a60205d54c4782157c0049b4. It was complicated to explain, not really useful and slightly backwards incompatible, all in all a bad trade off. --- feincms/content/application/models.py | 6 +----- feincms/module/mixins.py | 8 ++++++-- feincms/module/page/processors.py | 8 ++++---- feincms/module/page/templatetags/feincms_page_tags.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 940acfc5f..486a1946a 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -327,7 +327,7 @@ def process(self, request, **kw): appcontent_parameters=self.parameters ) else: - path = request._feincms_extra_context['extra_path'][-1] + path = request._feincms_extra_context['extra_path'] # Resolve the module holding the application urls. urlconf_path = self.app_config.get('urls', self.urlconf_path) @@ -356,11 +356,7 @@ def process(self, request, **kw): appcontent_parameters=self.parameters ) - # TODO actually determine the remaining part - request._feincms_extra_context['extra_path'].append('/') output = fn(request, *args, **kwargs) - request._feincms_extra_context['extra_path'] = ( - request._feincms_extra_context['extra_path'][:-1]) if isinstance(output, HttpResponse): if self.send_directly(request, output): diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 6e6ced3ed..daff34288 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -178,9 +178,13 @@ def process_content_types(self): extra_context = self.request._feincms_extra_context if (not settings.FEINCMS_ALLOW_EXTRA_PATH - and extra_context.get('extra_path', ['/'])[-1] != '/'): + and extra_context.get('extra_path', '/') != '/' + # XXX Already inside application content. I'm not sure + # whether this fix is really correct... + and not extra_context.get('app_config') + ): raise Http404('Not found (extra_path %r on %r)' % ( - extra_context.get('extra_path'), + extra_context.get('extra_path', '/'), self.object, )) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 36520a1f7..31fb8118e 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -13,7 +13,7 @@ def redirect_request_processor(page, request): """ target = page.get_redirect_to_target(request) if target: - if request._feincms_extra_context.get('extra_path', ['/'])[0] == '/': + if request._feincms_extra_context.get('extra_path', '/') == '/': return HttpResponseRedirect(target) raise Http404() @@ -25,15 +25,15 @@ def extra_context_request_processor(page, request): request._feincms_extra_context.update({ # XXX This variable name isn't accurate anymore. 'in_appcontent_subpage': False, - 'extra_path': ['/'], + 'extra_path': '/', }) url = page.get_absolute_url() if request.path != url: request._feincms_extra_context.update({ 'in_appcontent_subpage': True, - 'extra_path': [re.sub('^' + re.escape(url.rstrip('/')), '', - request.path)], + 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', + request.path), }) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 4689d5b06..a8fc36edd 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -248,7 +248,7 @@ def what(self, page, args): request = args.get('request', None) if request: # Trailing path without first slash - trailing_path = request._feincms_extra_context.get('extra_path', ['/'])[0][1:] + trailing_path = request._feincms_extra_context.get('extra_path', '')[1:] translations = dict((t.language, t) for t in page.available_translations()) translations[page.language] = page From 50d11840d4c1dbe235707746fbd464dd0c6d318e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 10 Oct 2012 18:03:01 +0200 Subject: [PATCH 0549/1590] Remove a now obsolete paragraph from the draft release notes --- docs/releases/1.7.rst | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index 0c4420bf8..f640694e6 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -134,19 +134,6 @@ Removal of deprecated features ``admin/content/mediafile/init.html`` has been deleted. -Nested ``ContentObjectMixin`` processing ----------------------------------------- - -FeinCMS now supports nested :py:class:`feincms.models.Base` subclasses -on a page, i.e. a content type with a ``process`` method inside an elephantblog -entry inside an application content. It's up to you to decide if this makes -sense or not -- - -Because of that, ``request._feincms_extra_context['extra_path']`` is now a -list, where the last element is always the remainder of the URL which is -relevant for the current content type. - - New deprecations ---------------- From b5d08a49398e3d40f3cc7c2a166716ee0959a79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Ba=CC=88chler?= <sb@feinheit.ch> Date: Thu, 16 Aug 2012 12:40:04 +0200 Subject: [PATCH 0550/1590] add comment to page pretender update comment to page pretender --- feincms/module/page/extensions/navigation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index caae94f00..721da27a9 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -56,6 +56,7 @@ def get_level(self): return self.level def get_children(self): + """ overwrite this if you want nested extensions using recursetree """ return [] def available_translations(self): From 4e4fa994f89f70ca04fa96c23febca8c360698c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= <simon@stellanera.com> Date: Tue, 21 Aug 2012 13:02:06 +0200 Subject: [PATCH 0551/1590] make datepublisher save aware datetimes --- feincms/module/extensions/datepublisher.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index b90048712..5430fafa4 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -42,13 +42,16 @@ def granular_now(n=None): """ if n is None: n = timezone.now() - return datetime(n.year, n.month, n.day, n.hour, (n.minute // 5) * 5) + return timezone.make_aware(datetime(n.year, n.month, n.day, n.hour, + (n.minute // 5) * 5), n.tzinfo) # ------------------------------------------------------------------------ def register(cls, admin_cls): - cls.add_to_class('publication_date', models.DateTimeField(_('publication date'), + cls.add_to_class('publication_date', + models.DateTimeField(_('publication date'), default=granular_now)) - cls.add_to_class('publication_end_date', models.DateTimeField(_('publication end date'), + cls.add_to_class('publication_end_date', + models.DateTimeField(_('publication end date'), blank=True, null=True, help_text=_('Leave empty if the entry should stay active forever.'))) cls.add_to_class('latest_children', latest_children) @@ -68,7 +71,8 @@ def granular_save(obj, *args, **kwargs): if hasattr(cls._default_manager, 'add_to_active_filters'): cls._default_manager.add_to_active_filters( Q(publication_date__lte=granular_now) & - (Q(publication_end_date__isnull=True) | Q(publication_end_date__gt=granular_now)), + (Q(publication_end_date__isnull=True) | + Q(publication_end_date__gt=granular_now)), key='datepublisher') def datepublisher_admin(self, page): From ce754ccd722c8f8f0f1ab0898aa750295af1e3de Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Sat, 13 Oct 2012 08:22:46 +1100 Subject: [PATCH 0552/1590] Don't require page classes to have request/response processors. See #241 --- feincms/module/mixins.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index daff34288..2def20cc1 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -126,7 +126,7 @@ def run_request_processors(self): also return a ``HttpResponse`` for shortcutting the rendering and returning that response immediately to the client. """ - if self.object.request_processors is None: + if not getattr(self.object, 'request_processors', None): return for fn in reversed(self.object.request_processors.values()): @@ -140,7 +140,7 @@ def run_response_processors(self, response): processors are called to modify the response, eg. for setting cache or expiration headers, keeping statistics, etc. """ - if self.object.response_processors is None: + if not getattr(self.object, 'response_processors', None): return for fn in self.object.response_processors.values(): From 096a2d615c96fc911c3eecdd7b42973dbdb81f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= <simon@stellanera.com> Date: Sun, 14 Oct 2012 15:50:24 +0200 Subject: [PATCH 0553/1590] do not crash if site module is not installed --- feincms/translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/translations.py b/feincms/translations.py index 82bcbcd85..d2793e3e2 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -185,7 +185,7 @@ def get_translation_cache_key(self, language_code=None): """Return the cache key used to cache this object's translations so we can purge on-demand""" if not language_code: language_code = translation.get_language() - return (('FEINCMS:%d:XLATION:' % settings.SITE_ID) + + return (('FEINCMS:%d:XLATION:' % getattr(settings, 'SITE_ID', 0)) + '-'.join(['%s' % s for s in self._meta.db_table, self.id, From ee47008d7724518c7ff46705e45ea521ebee7f7d Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 15 Oct 2012 11:14:18 +1100 Subject: [PATCH 0554/1590] Display explanatory text when creating translations of pages. --- feincms/module/page/modeladmins.py | 24 +++++++++++++++++-- .../templates/admin/feincms/item_editor.html | 12 ++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index af5571fab..37fe88fe6 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -109,8 +109,28 @@ def _actions_column(self, page): return actions def add_view(self, request, **kwargs): - # Preserve GET parameters - kwargs['form_url'] = request.get_full_path() + kwargs['form_url'] = request.get_full_path() # Preserve GET parameters + if 'translation_of' in request.GET and 'language' in request.GET: + try: + original = self.model._tree_manager.get( + pk=request.GET.get('translation_of')) + except (AttributeError, self.model.DoesNotExist): + pass + else: + language_code = request.GET['language'] + language = dict( + django_settings.LANGUAGES).get(language_code, '') + kwargs['extra_context'] = { + 'adding_translation': True, + 'title': _( + 'Add %(language)s Translation of "%(page)s"' % { + 'language': language, + 'page': original, + } + ), + 'language_name': language, + 'translation_of': original, + } return super(PageAdmin, self).add_view(request, **kwargs) def response_add(self, request, obj, *args, **kwargs): diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index c3743bd64..606b58b16 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -34,6 +34,18 @@ {% endblock %} {% block form_top %} + {% if adding_translation %} + <div> + <p> + {% blocktrans %} + <strong>Note:</strong> if you save this new version + ({{ language_name }}) without adding any content, content from + the original page ("{{ translation_of }}") will be copied + automatically. + {% endblocktrans %} + </p> + </div> + {% endif %} {% with original.available_translations as translations %} {% for translation in translations %} {# look for something the translation extension's available_translations method might return #} From b5df659ad801df958a26462a8925f0d41e374035 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 15 Oct 2012 11:32:29 +1100 Subject: [PATCH 0555/1590] Seems better to show a single translation inline initially, with "add another". -- otherwise you get n-inlines each with the language set to the original. --- feincms/translations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/translations.py b/feincms/translations.py index 82bcbcd85..f9eae2d7a 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -293,6 +293,7 @@ def admin_translationinline(model, inline_class=admin.StackedInline, **kwargs): ) """ + kwargs['extra'] = 1 kwargs['max_num'] = len(settings.LANGUAGES) kwargs['model'] = model return type(model.__class__.__name__ + 'Inline', (inline_class,), kwargs) From a7911b64fa66159c505f5be54d57e7e496083175 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 15 Oct 2012 20:06:56 +1100 Subject: [PATCH 0556/1590] One translation per language per item seems to make sense? --- feincms/module/medialibrary/models.py | 1 + feincms/translations.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index bcdcab2e1..a71f7d4ab 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -234,6 +234,7 @@ class MediaFileTranslation(Translation(MediaFile)): class Meta: verbose_name = _('media file translation') verbose_name_plural = _('media file translations') + unique_together = ('parent', 'language_code') def __unicode__(self): return self.caption diff --git a/feincms/translations.py b/feincms/translations.py index f9eae2d7a..03f20ca72 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -261,6 +261,9 @@ class Inner(models.Model): editable=len(settings.LANGUAGES) > 1) class Meta: + unique_together = ('parent', 'language_code') + # (beware the above will not be inherited automatically if you + # provide a Meta class within your translation subclass) abstract = True def short_language_code(self): From bd9fc02845126052367aa376cb9f6eb0ec10d9e6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 16 Oct 2012 17:47:50 +0200 Subject: [PATCH 0557/1590] Fix get_navigation_url now that redirect_to has an overloaded meaning --- feincms/module/page/forms.py | 1 + feincms/module/page/models.py | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 63576f421..eb36d01ee 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -24,6 +24,7 @@ class RedirectToWidget(ForeignKeyRawIdWidget): def label_for_value(self, value): match = re.match( + # XXX this regex would be available as .models.REDIRECT_TO_RE r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$', value) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index b0bf50b12..8554f7570 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -24,6 +24,11 @@ from feincms.utils import path_to_cache_key + +REDIRECT_TO_RE = re.compile( + r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$') + + # ------------------------------------------------------------------------ class PageManager(models.Manager, ActiveAwareContentManagerMixin): """ @@ -294,7 +299,10 @@ def get_navigation_url(self): Return either ``redirect_to`` if it is set, or the URL of this page. """ - return self.redirect_to or self._cached_url + # :-( maybe this could be cleaned up a bit? + if not self.redirect_to or REDIRECT_TO_RE.match(self.redirect_to): + return self._cached_url + return self.redirect_to def cache_key(self): """ @@ -331,9 +339,7 @@ def get_redirect_to_target(self, request): return u'' # It might be an identifier for a different object - match = re.match( - r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$', - self.redirect_to) + match = REDIRECT_TO_RE.match(self.redirect_to) # It's not, oh well. if not match: From d5527f53605232adb25599c710eb3798f0df3b52 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Thu, 18 Oct 2012 15:34:28 +1100 Subject: [PATCH 0558/1590] Improve translation cloning UX and reduce magic. --- feincms/module/page/modeladmins.py | 3 ++- feincms/templates/admin/feincms/content_editor.html | 12 +++++++++++- feincms/templates/admin/feincms/item_editor.html | 12 ------------ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 37fe88fe6..6a9f7c128 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -138,7 +138,8 @@ def response_add(self, request, obj, *args, **kwargs): if 'parent' in request.GET and '_addanother' in request.POST and response.status_code in (301, 302): # Preserve GET parameters if we are about to add another page response['Location'] += '?parent=%s' % request.GET['parent'] - if 'translation_of' in request.GET: + + if 'translation_of' in request.GET and '_copy_content_from_original' in request.POST: # Copy all contents for content_type in obj._feincms_content_types: if content_type.objects.filter(parent=obj).exists(): diff --git a/feincms/templates/admin/feincms/content_editor.html b/feincms/templates/admin/feincms/content_editor.html index 6f4abb198..77e007a7d 100644 --- a/feincms/templates/admin/feincms/content_editor.html +++ b/feincms/templates/admin/feincms/content_editor.html @@ -8,7 +8,17 @@ {% for region in original.template.regions %} <div id="{{ region.key }}_body" class="panel"> <div class="empty-machine-msg"> - {% trans "Region empty" %} + + {% if adding_translation and forloop.first %} + <div> + <p> + <input type="checkbox" name="_copy_content_from_original" checked="checked" /> <label for="_copy_content_from_original">{% trans "Copy content from the original" %} ("{{ translation_of }}", {% trans translation_of.get_language_display %})</label> + </p> + </div> + {% else %} + {% trans "Region empty" %} + {% endif %} + </div> <div class="empty-machine-msg" style="margin-left:20px; margin-top:20px;"> {% if region.inherited %} diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index 606b58b16..c3743bd64 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -34,18 +34,6 @@ {% endblock %} {% block form_top %} - {% if adding_translation %} - <div> - <p> - {% blocktrans %} - <strong>Note:</strong> if you save this new version - ({{ language_name }}) without adding any content, content from - the original page ("{{ translation_of }}") will be copied - automatically. - {% endblocktrans %} - </p> - </div> - {% endif %} {% with original.available_translations as translations %} {% for translation in translations %} {# look for something the translation extension's available_translations method might return #} From 235d9d6f2f8d5452470dd7680ee3f6577254ec80 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Thu, 18 Oct 2012 20:41:29 +1100 Subject: [PATCH 0559/1590] Add id to checkbox --- feincms/templates/admin/feincms/content_editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templates/admin/feincms/content_editor.html b/feincms/templates/admin/feincms/content_editor.html index 77e007a7d..4fc9dee71 100644 --- a/feincms/templates/admin/feincms/content_editor.html +++ b/feincms/templates/admin/feincms/content_editor.html @@ -12,7 +12,7 @@ {% if adding_translation and forloop.first %} <div> <p> - <input type="checkbox" name="_copy_content_from_original" checked="checked" /> <label for="_copy_content_from_original">{% trans "Copy content from the original" %} ("{{ translation_of }}", {% trans translation_of.get_language_display %})</label> + <input type="checkbox" name="_copy_content_from_original" id="_copy_content_from_original" checked="checked" /> <label for="_copy_content_from_original">{% trans "Copy content from the original" %} ("{{ translation_of }}", {% trans translation_of.get_language_display %})</label> </p> </div> {% else %} From 5fd9fb7014ee08fdc0ee486950e876cd44578984 Mon Sep 17 00:00:00 2001 From: Marco Cellarosi <marco@pc-09.(none)> Date: Tue, 23 Oct 2012 08:57:55 +0200 Subject: [PATCH 0560/1590] Fixed Issue #351 --- feincms/templatetags/feincms_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index b4bb76d18..444b15e11 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -56,7 +56,7 @@ def feincms_frontend_editing(cms_obj, request): {% feincms_frontend_editing feincms_page request %} """ - if hasattr(request, 'COOKIES') and request.COOKIES.get('frontend_editing'): + if hasattr(request, 'COOKIES') and request.COOKIES.get('frontend_editing') == 'True': context = template.RequestContext(request, { "feincms_page": cms_obj, }) From c4172c0bee766355dcedd5a849ced82eb242524e Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Fri, 26 Oct 2012 14:27:21 +0200 Subject: [PATCH 0561/1590] Remove 'frontend_editing' cookie on Stop editing FIX #351 As mentioned in https://github.com/feincms/feincms/pull/350#issuecomment-8645705 --- feincms/module/page/processors.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index d2d71ef88..c40e686c6 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -39,7 +39,10 @@ def frontendediting_request_processor(page, request): except ValueError: enable_fe = False - response.set_cookie('frontend_editing', enable_fe) + if enable_fe: + response.set_cookie('frontend_editing', enable_fe) + else: + response.delete_cookie('frontend_editing') # Redirect to cleanup URLs return response From c45cbb9810cd1fb10c2510de33c4012515ef6cfd Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Fri, 26 Oct 2012 14:29:39 +0200 Subject: [PATCH 0562/1590] PEP8 cleanup --- feincms/module/page/processors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index c40e686c6..0f7becf87 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -24,6 +24,7 @@ def redirect_request_processor(page, request): return HttpResponseRedirect(target) raise Http404() + def frontendediting_request_processor(page, request): """ Sets the frontend editing state in the session depending on the From 117dcee981da587bb89e9cac7e5a9b59866b4ed1 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Fri, 26 Oct 2012 16:46:34 +0200 Subject: [PATCH 0563/1590] Update frontendediting_request_processor docs --- feincms/module/page/processors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 0f7becf87..20de6be1c 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -27,7 +27,7 @@ def redirect_request_processor(page, request): def frontendediting_request_processor(page, request): """ - Sets the frontend editing state in the session depending on the + Sets the frontend editing state in the cookie depending on the ``frontend_editing`` GET parameter and the user's permissions. """ if not 'frontend_editing' in request.GET: From 60022df9ce41110f96a56f8d4a7015e964390f56 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Fri, 26 Oct 2012 16:49:33 +0200 Subject: [PATCH 0564/1590] Add tests for frontend editing. Also fix invalid invalid client test for frontend editing that worked only because fe_box is never in 404 page. --- feincms/tests/page_tests.py | 51 ++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 8dd36dd04..ae6d9ec23 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -32,6 +32,7 @@ from feincms.context_processors import add_page_if_missing from feincms.models import ContentProxy from feincms.module.medialibrary.models import Category, MediaFile +from feincms.module.page import processors from feincms.module.page.models import Page from feincms.templatetags import feincms_tags from feincms.translations import short_language_code @@ -589,12 +590,56 @@ def test_15_frontend_editing(self): self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') request = Empty() - request.COOKIES = {'frontend_editing': True} + request.COOKIES = {'frontend_editing': "True"} - self.assertTrue('class="fe_box"' in\ + self.assertIn('class="fe_box"', page.content.main[0].fe_render(request=request)) - self.assertFalse('class="fe_box"' in self.client.get(page.get_absolute_url() + '?frontend_editing=1').content) + def test_15_b_client_frontend_editing(self): + self.create_default_page_set() + page = Page.objects.get(pk=1) + self.create_pagecontent(page) + + page.active = True + page.template_key = 'theother' + page.save() + + # FEINCMS_FRONTEND_EDITING is False by default + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=1', + follow=True) + self.assertNotIn('class="fe_box"', response.content) + self.assertNotIn('frontend_editing', self.client.cookies) + + # manually register request processor + # override_settings(FEINCMS_FRONTEND_EDITING=True) wont work here + Page.register_request_processor( + processors.frontendediting_request_processor, + key='frontend_editing') + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=1', + follow=True) + self.assertRedirects(response, page.get_absolute_url()) + self.assertIn('class="fe_box"', response.content) + self.assertIn('frontend_editing', self.client.cookies) + + # turn off edit on site + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=0', + follow=True) + self.assertRedirects(response, page.get_absolute_url()) + self.assertNotIn('class="fe_box"', response.content) + + # anonymous user cannot front edit + self.client.logout() + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=1', + follow=True) + self.assertRedirects(response, page.get_absolute_url()) + self.assertNotIn('class="fe_box"', response.content) + + # cleanup request processor + del Page.request_processors['frontend_editing'] def test_16_template_tags(self): # Directly testing template tags doesn't make any sense since From fe742d287bea1bd89f43a36113c8fde120445c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= <simon@stellanera.com> Date: Sun, 4 Nov 2012 15:44:22 +0100 Subject: [PATCH 0565/1590] fix typos: i.e. stands for d.h. e.g. for z.B. --- docs/integration.rst | 2 +- docs/page.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integration.rst b/docs/integration.rst index 66676b49b..0f05698b9 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -183,7 +183,7 @@ Returning content from views Three different types of return values can be handled by the application content code: -* Unicode data (i.e. the return value of ``render_to_string``) +* Unicode data (e.g. the return value of ``render_to_string``) * ``HttpResponse`` instances * A tuple consisting of two elements: A template instance, template name or list and a context ``dict``. More on this later under diff --git a/docs/page.rst b/docs/page.rst index 4bd580bf4..65d4cf129 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -10,7 +10,7 @@ FeinCMS is primarily a system to work with lists of content blocks which you can assign to arbitrary other objects. You do not necessarily have to use it with a hierarchical page structure, but that's the most common use case of course. Being able to put content together in small manageable -pieces is interesting for other uses too, i.e. for weblog entries where you +pieces is interesting for other uses too, e.g. for weblog entries where you have rich text content interspersed with images, videos or maybe even galleries. From 15b4c3eb13006255b8ef7df7701717aea3c223bc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 5 Nov 2012 15:55:31 +0100 Subject: [PATCH 0566/1590] Blog entries do not have a redirect_to attribute --- feincms/module/extensions/translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 19adf8c58..5ad728788 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -99,7 +99,7 @@ def translations_request_processor_explicit(page, request): # ------------------------------------------------------------------------ def translations_request_processor_standard(page, request): # If this page is just a redirect, don't do any language specific setup - if page.redirect_to: + if getattr(page, 'redirect_to', None): return if page.language == translation.get_language(): From d66d09a092d063a702d571b20553c0deed60a546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= <simon@stellanera.com> Date: Sun, 4 Nov 2012 15:44:22 +0100 Subject: [PATCH 0567/1590] fix typos: i.e. stands for d.h. e.g. for z.B. --- docs/integration.rst | 2 +- docs/page.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integration.rst b/docs/integration.rst index 66676b49b..0f05698b9 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -183,7 +183,7 @@ Returning content from views Three different types of return values can be handled by the application content code: -* Unicode data (i.e. the return value of ``render_to_string``) +* Unicode data (e.g. the return value of ``render_to_string``) * ``HttpResponse`` instances * A tuple consisting of two elements: A template instance, template name or list and a context ``dict``. More on this later under diff --git a/docs/page.rst b/docs/page.rst index 4bd580bf4..65d4cf129 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -10,7 +10,7 @@ FeinCMS is primarily a system to work with lists of content blocks which you can assign to arbitrary other objects. You do not necessarily have to use it with a hierarchical page structure, but that's the most common use case of course. Being able to put content together in small manageable -pieces is interesting for other uses too, i.e. for weblog entries where you +pieces is interesting for other uses too, e.g. for weblog entries where you have rich text content interspersed with images, videos or maybe even galleries. From e6d2a8ab2e0ad321c6fdb3563db25af6538ef8ca Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 13 Nov 2012 16:12:32 +0100 Subject: [PATCH 0568/1590] Fix #366: Wrong number of parameters for get_inline_instances in Django 1.5 --- feincms/admin/item_editor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 17317da8e..ff26d7b31 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -61,8 +61,9 @@ def __init__(self, model, admin_site): super(ItemEditor, self).__init__(model, admin_site) - def get_inline_instances(self, request): - inline_instances = super(ItemEditor, self).get_inline_instances(request) + def get_inline_instances(self, request, *args, **kwargs): + inline_instances = super(ItemEditor, self).get_inline_instances(request, + *args, **kwargs) self.append_feincms_inlines(inline_instances) return inline_instances From 83d3efeee82644860096076aa0f705a1bfa64f07 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 13 Nov 2012 16:32:21 +0100 Subject: [PATCH 0569/1590] Adapt test to ImageContent change --- feincms/tests/cms_tests.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/feincms/tests/cms_tests.py b/feincms/tests/cms_tests.py index 8d4641a8b..c2f928b16 100644 --- a/feincms/tests/cms_tests.py +++ b/feincms/tests/cms_tests.py @@ -32,10 +32,6 @@ def test_01_simple_content_type_creation(self): ExampleCMSBase.create_content_type(ContactFormContent) ExampleCMSBase.create_content_type(FileContent, regions=('region2',)) - # no POSITION_CHOICES, should raise - self.assertRaises(ImproperlyConfigured, - lambda: ExampleCMSBase.create_content_type(ImageContent)) - ExampleCMSBase.create_content_type(RawContent) ExampleCMSBase.create_content_type(RichTextContent) From c2908735afb1f2ee8f101468d7619e9998655ac3 Mon Sep 17 00:00:00 2001 From: Jonas <jvp@jonasundderwolf.de> Date: Thu, 15 Nov 2012 14:50:01 +0100 Subject: [PATCH 0570/1590] Avoid error for unbound local variable in tag --- feincms/templatetags/applicationcontent_tags.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index 3957020ca..ca32950dc 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -58,6 +58,7 @@ def render(self, context): except NoReverseMatch: if self.asvar is None: raise + url = '' if self.asvar: context[self.asvar] = url From 9597eb41e9dd6d166882a473f71a9b6dc517ed72 Mon Sep 17 00:00:00 2001 From: Richard Bolt <richard@richardbolt.com> Date: Mon, 19 Nov 2012 23:56:28 -0800 Subject: [PATCH 0571/1590] Vimeo flash embed player was deprecated. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated to the new embed code for Vimeo. See: http://developer.vimeo.com/player/embedding for more information. I've kept the dimensions the same as with the deprecated megaloop player. --- feincms/templates/content/video/vimeo.html | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/feincms/templates/content/video/vimeo.html b/feincms/templates/content/video/vimeo.html index bf2a848fe..39cb580b0 100644 --- a/feincms/templates/content/video/vimeo.html +++ b/feincms/templates/content/video/vimeo.html @@ -1,6 +1,2 @@ -<object width="650" height="365"> - <param name="allowfullscreen" value="true" /> - <param name="allowscriptaccess" value="always" /> - <param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" /> - <embed src="http://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="650" height="365"></embed> -</object> +<iframe src="http://player.vimeo.com/video/{{ id }}" width="650" height="365" +frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> From ed576265beda2550cc17ea311ffd326d4e3d6f8f Mon Sep 17 00:00:00 2001 From: Cellarosi Marco <cellarosi@gmail.com> Date: Tue, 27 Nov 2012 23:57:24 +0100 Subject: [PATCH 0572/1590] Reset personal data --- feincms/locale/it/LC_MESSAGES/django.mo | Bin 11781 -> 13731 bytes feincms/locale/it/LC_MESSAGES/django.po | 332 +++++++++++------------- 2 files changed, 157 insertions(+), 175 deletions(-) diff --git a/feincms/locale/it/LC_MESSAGES/django.mo b/feincms/locale/it/LC_MESSAGES/django.mo index a9d7c656a6f461db6d37c2638f5c60afd4735e4c..a4fa53cb82c72b091541e8889201b717c7700f6a 100644 GIT binary patch literal 13731 zcmbW736xw%b%qNsV8r4L69O1NgM~&|)6z(?F=NR_(n#`vmO(R;u^o_Jcfam=sQbP4 zTV^zh*}TWtAz%pD1UrCPZI+mTF<=aKyg>+@U=Ac45;)0WJ%PiLg!LrfUsbQWH8L^e z9o_z4)vM*!t$T0Xx}$$N;ixwoo`;}kLe0k-^Q6ZZbK4VDYs|NfGv*}l+u$?6{|1i- zPvqw`a4D#!F9MGQ&j&TmMc|Xc1EBg{1*+Y<z+=IWfJcL$1=a6<a18uB2n*&n9*;c1 zm_MSt1Y80>8`Sqvkbh<^KNH|q@EGt~@bTcALCteB_$2Vd;8Vf7z!vy0$Uk%TiEe#6 zz-5%1;8VbB!RLbS0LAx%AWJu21)l(Z2h@B&1;x*=L9OQqIv3zE;8EZ!!N-A@`tmj4 zb11(aRQr#D8t+c<>EM0fTJT%o8Q@6>pI7r@@Q=ZLp!himGNri+)cW2A-UPlM)cVh3 zv1+#qJPX_liqE(D`kTRxly3tizaN9*b1lNwy4HajXEXR#a3?6fz6WaFlb>cx0FHrn z9#G@&1!-bhp!&ZGlpL=1->(DDr2HoEBJd0T`!W`%_A5ZOKhxvcpvHe8sPVUhlHZK~ zegG8TuLQM@E5Hrl=fNw$CnD4p;2S~d*WF+Z{0Z0q1C(<$csaNRyaUucKLoWuKLs`a zFTkzf(J1#ia68Bl<{D7zeK&~c&0V1O^DChE`d3ineHWBH{K$X*EhsrY{$#hmCxdK( zSq*C5Nl^WFg3|l*LG4T3<9<+l6`=P2wV>L+-k0Cv@!g>0`ceP=E?<8iC^>%x6u)2h z<$w41eNcS-2-LVg2gS#4K=JXoXSx2zfg1lLkEeKC4yykek1qfvhjT&ky9HFg8ILaq zHSR2^bzKaKzgKy@4AlHrd%PZ$ylw&||Br!M#}`4_=|6#*=LaCJ#QXx(cuP)k@;(-n z-#HD`xFewEUju6Xb)ec$`tLhHt>*$z>)7kdEl~YBpzO5t->(71#~Xb8J3+1Y4p8HN z4ivxt;LHE)%ijex{?9<Q{}rftj|$vAECDs&3846U2B`fBK<U>AsP@kXHO_ia?Iu9= zn*_zzE>Lo5fcjp7>UR*-ysrVZo@+pjdow7$KLo1%r@$k?&w}cAFDN-a1Zv)gL5=?n zaQ9=3`43RzZF;sl4_*rDdjYNluLR|<KMsn|`$3j&z67e@kHP1HM`8T940AfD`Uz0{ zTmXuXmxCL@rZ2x2lzcu2%HBQ(YJCs+`mcbR=NsS*_-p@t>NK}M7lJw`TA=i40fZHE z75Jy%2SD-t+@;R`&jd#(Zv(ZzCHOq>wV>8}8z}xi14^!61J&+3pyc*b@M!Rt;5_(0 zpyV;n;`RMCpvJih<deAp)c3nV@$n#dD)@EqJn&cG25{3dcYa&}Qe|!ir3d$en6&vC zsP+9Pcn5eSix6L*0#*M2D1N>Q9s_P)?)caP?xZ{mw!lw-j|Wd-(Q3Ec<7)6W%4dU9 z;P*g8ZC-G?<L70d=D8ev9Qa01a=sDNcz1!4%LD%V7eVdwSHS{&+6wpmI`9dUuLmCs z-V7cEz6aF)-wJA+yTKZGpD+I$)V#j}#orO5oPFRlcq4cNI0mkzlg_V}$G3wElphAq z0C%k9tO73wHUE8}=KFh4>-$G=Klm;1TyWbe=fAG?c#FqRgHPo9!=T3bw#V;*)*k%# zqhLyY@OY0S9?u2UZx6Txd>JS?&U(x|UII$Luk?6>ufGk{JRb*-2fyI!zX@vG@A~>5 zfs(HdQOW&iP~VRSwf|4^<x@S5fZ}H*sP^Na`fmZn--|)*({51fk3q?A&f_JZ#=R7L zGWa@B{cZ#`?=2p01;zjEpxQqGYP>Il+J|p~$AdovW&gkRc=8%ozaBh}`kkQK@AKsZ z6u++q2{Fv&p!mB9)cCi6;^S|?W5G}O@`K=sl)vQ5{|1V$AAsurGf?aJCHQpk$hA&R z&jK~ia!}{oCSQLMD85=A3y+tA8uu?i>GKVs#(f7UzHasPw|o2~sP)_fS~-DQ_m}<m zZ+rYcsCGXAwQv6gs@)MNz3@a(>o^V6JkJBQ{xMMeZve&bMWFUS1~py*9sw?Z>VJv< zeyJ~C2Wp(_L5>lVK)5LL8E7+f3G@<3zF5y5=tIysD)5}`z<dB)3Vqa<*>3w>!|$8@ zyWnNeMbJsm0qDh$p0`1N35}@0^IGWb(1p;)p$vKzGzIO1V(1>|8Iac3g0vqiAwBCH z*x$4G)!x1ydWWrH|G-Z{1tfW&58VLiDWO+F5wr!m3Az^2Bi-rRH+0aWpyS_j@D0%2 zzO1uI`k`kZbTKpwJqXD^eGIx9(sPUhv)$vLgX7R7bTjmFNY5yA6?7$ZE2QV|pgW<@ zLhGR#v<kWcdOoD*&m5RKI1POgdLgtGlFobr((@+{?C<ONJrimU)m_i~iO_p|-HX8c zp)n|g-U2-v(lg<}eAwfH$K@X13El?16ly@y*}I@ip@$$n$2zdTZykEq>y6O6hw5Yt z^N@VSCg`sqJ-0(oh8}=+L3%z2T>$+pGzZ-R4L_fw@Jwj8uiOhh71{`W1bQ!YB&6qP z=rm{sdJXg(=oIKl(5Imdke>UX<De9J7j!zLCxG6l7oJlc*x$eAcL(%5TXH|I7<zve z@7ti`p?jef(8-XV7eKFua3wZY0c>pYCa?|N0Ud-M3tb1j54sF`KXf^C26O_XXARV| zZ|-M5@D#lU8yAA5BdxeoMA_aVE;`ZjJTOZ~8fmv1CB@!GS|$ZmzMR+0(q=&OC=cRp zFU^XmX_n@}Y?uf2C`y8EIu|vAA`QYIiROb|n#V<)CN(pXq(LL>sj%E^Xf{Pbn54yQ zl)=GVl-1Kb+M9%3IItfZvvH>x^ul&zi`}Rhhkk0tZ-hnEPO}C3O;g21)U|~}KDJnw z+0f~TSVU5=s33;<gn8-0VzRUw6tmQ6svvF!?RYMN<Bd@(%_6fgPC};HSa$XYWv`Ql zupL}DIb~THH=Dx7ETin+wT;)L5p@JCD`-ZYs9-#?b$HbZ#MKDPTn)reFU-VQ+6uxV z=tN=8dlCgsJQ}0MAb!Q0X2S$dm*&R5@wwOGtJ#!xI$@7Ni!4$pX~h|fOAlqnOTjNZ zs^(^=;3f~kvPipO5jVn4XJH_yS}>Ca>~5CDO(u}Q>d|aC7pG;mA_&>dJncr6jA1v6 zU<ppbB!@Zn-Aqt1S`TyN)hp|rIG>G^wwZ8(%7KP9<WObU+v}8B*g+>IqP&sCR)Zv` zxGT+=h?{|=T_(*a%Zo5+N(C7f#`7X88&3N+HxYB11X`o9g<-xnALyy071|cKE;F=x zi?s=}r4#0}=DeBh+k&~U6F2Qjf?k$3%Z6pvSx7UO53_`M^I9;a{fmMunv2m(6db*w zAFV3|tVf-69`Q-RY-OC3^c`pI-6+plSk8jaL(u%>h1C2!gli_-iF#<r#T-@Bn@KB| z$s~`mLN+*VCeaVC0c=v)XfQ>qWOHj~TNKVk0qRq*(=9tNYM3nq`D|KZeMod62oWN! z#4Ouib+Q`Zdh#Vuw^&{wv7_`d_J?sgsA|c2YGwzj(st5|4q%44G-3w=s$5IZWv+T8 zRYLqbFmdOD@HrIXq*oT!=A3<+oz`=tRv&V+bD)^WC(PPWA)BlP8zYu1nQ4edr$l#A z$9xu6u{24t9<}2{TZcQswq0e!D*|!G83vscYj6Y3Nb|#13uVOuFi<;4GFY8P$;-OD zNxn>dSb*4@m%lMn6I+62+9>5+%@l0{>vbjFpq{1kY+EoNC(U%e7EI#|13as1QD0ya zTVdHLYIKylFjFahVv`e-nabE#%S^6Kt(QfC#yeGG^;y)A_0j<Td6E2OM-o9=e+A27 z*hd?Je#j?%v_Yi!X4mv|(2Cf~>LoY3BI{Ec&Vf~K>)c>nJquQzV_mfUgn-#HEkkF- zz;3L|T8CYyN&B3oBRQ_85$(;`z%;>P)~)oP<i`3Z(V)H43*UaIdF}thSijSdqd%8{ zoRnSVVrPa?@3PD~lcOLm0V~%-9iQ69joDxZYcbP^!c0eD)|dt4DD7#b?M7j}v0^*; zRQVZnCW~|;^hH;zx@o(+IIj+VKf_ZtrTCS)S}n8+Qk{hhX^9hI95%gC;)=TQLFa%5 z8n3aFrkS249B7n9uD5wJEp4AJ(q15c%PeNPtaszW%=E3(PS-zfV7VEir3Ln47d?Y6 z?9Wd%GqB7-hN^dB&P4XsE+UkxQN*&smRp>CDVEc=t-J=6b=yKCYLI@D;b3AuCN!x0 zj#F-QuR4vYIAh$7kYQo1IKnf+Mdj6VZ6EHTh;iNo2hDJy7HkN-mV1ZjY}n3~CY-BG zI2Y$}oqfO#wV+uYpH}Xnq83}1u=&=A{A5}OGvie3N!{U$Z7$&N_7i&HAHt+^)*9zg z8@uSjyZ50UTAL1O`6O}HjuI9qZ5nJkf=c}a1NFmE#>sxkFbvR~qGXkfF^6DMew$Ic zB8Y2IZ9JGQir)CjmGkrSHQ%s?yI(mU7LD0+=hh$WzG5uv9h}&8;VQS{YLj|d)I-^v zLW(!<62X3S;MscAF8iZ}`7~=<qoI#fDK~q>CBGa@RlIP%SCE`DrLV2lk);HDS}0rJ zVA-&<&j&V9a~}#2HTKuj13_5F%4_BV8aC5pSwXmrgI4n-(qXKFvKM9DIG0mKz0&|w z&_TpbINxllh%<-|DC`beAwhVPh#_D63E5!(zTO4thqR7+cvpgJJc_oS2`#FqTR_4_ z2ZfwY*z0wO0&VCv^j<|V!{4hqhMI%1P-;CCVdbXI3A*3-3jk<CS>lE2b-`4pJugWC zW759vAq5({(6vHm{)5s&PXngCg)DB*7N%h%(56G3b_&7_KcN}Y7Q<1S7|Gj2U3fQ9 zBKDi6AEo4`RRx8*`565WOtez>mg5oKTLA<1EjKPYwZ9aSA;Y2MuO5cob;f6^Fo_r3 zoOdjy6SWE>i!$BtK+Rqyax-vUL$AZa{vFlBJ@sDTs0KFUD!fJTIc>%*zxPgTx|o?E z^Y2T?5MvsJ;8yb+28-fmg}Ya@VebmM8_B!aAHQcR=Tz7*hRaKwnCh-*u<=pq83t9Z zw%m{Iz=e@^JBKS2v<)hW@tVed)*IGrvQW{cy#o%v=cYP&usq)FnVjkDwPxUyDd%89 zhm6PE<ejo@I5-tKnS7zEePSBB&_Wty>~9XV`KhjG)k~j|#T9Cc@!9jj{RV`EgEt=# zb;@pHhD?l5Zn(%OQpU1ptlM?J);qh`9B`+Pjj2Yp@~JG<Vn!#MqkCL@I38??;$+kI z=_R`&d7aVic{^^7ZY<mR=uA2uEScIlGion-h-P#G^BNCUuNqrDy6UXav9Vxm&G;E> zPG7Zp)hZf}66G-E;qBH2W6vL7J9hf2G1_fI|3_#1oiWYEgQ+m>q`?H2aK5>_#OO>E zcE^Kl8+L5ny<zL-VBNNDFYLs%G;5#JZ!?ayEZIJ}ee+-`W3^RFHo4s&ok2L`c6(P^ z<vUxab%ujqzk6oO=vjky;-nR2qnnckCZQ|ZS#?I9vX|1)Ex4$BJV@LfHDAB_?7+RQ zA4!5!*9T+EmvHIjR)@>@{Sqv3Kf&VjE2z2>Ecae^&--*6<7mh+6#If(DHHN6WjYty zOv^!}8`T1vYiV*-&AGJ1A?cQOJ1&!U+<yu1^jW&-rcJ<EHRLMK<pEVj?1M_{_qyCa zIL^t%bYf2V%99T@6F<7V$<9b64EhhZo=AJCnb8%+{>DMv?-4UQ$s$>Q%sOLCI=Hxu zShI`^j#dzzA%&>nTvVug3!c_xYT}ec3C0^Do4|6+$?4NHikr-aB;oEGa!*E%n1Gyl z)QP)F^Hk{zvHi&32@7>|BaY#~Zp^YR?{|Acj1+TGCm=yA9onQ~z{$DlRI5(AI5gY6 zhg}+w#tFN1a$7~*OZ^hb?8K!VsUBslh)fRg0UkT9c(r@oml^C<=`DE2v9m%yl%hAs z8MiXR=Sr@`X#GTwmW1L=Mcm`(5V{0Gbkc}f-|d`HjgUR)D~C3CXuDjhM<-CTv|QOd zk66X|lI3ZHu6DB%@*=J4=XY3`6>aPfXV+;`NgTIU26U=#H-M~960pyxO5TV|&h$#6 z+-5pT^rZb7mV-Ek7~GsI;iHYR;+;&i>}Hf43~ky6iMzDVw$LYi90xY%GK*lz{>VUB zN|pTy=j7ZFp)^rzm;RI0L6jMh78UXE28CE;s!$7a)<}yoKRYnp6b5yF%21XmtM|-H z3M1}?oGmsJ6b5Y>p`BWDx&+mLS9F+U5O*eH(?KzUvfjcfl(WuConV9+5uMEr5!vrh zsj@MtHDObrXg-wn4YaGt<%fOfhFlRyRurU)5D<!#bK+%0y?FFSERC8gQ)aQ2%w!?v zXWL<Zb197B%{W3y7HOH}jxdN3jAMDtVEQgyWR1(kAWl0rFO%Q%Ml6})<-|s%p*Dvd zlV!?tjL}D!EN+X7;FwcMC23NBsd892M^@U?9Be^4m$3xxBDI}mx_cpOVkh?3sW!Jg zm}rovl(*7SY@$ic$-{&hFI*Rv#YxPN2$6y^*%+f7SuD*g6pqDm85-ZFn=r_i$nBB3 zi4jYN3FZieu0tYVH0gjk4SaSKEaOhz=Q}nNKH-!Gq@N5o9i6F%I0@~TX9|l`Xvm$| zrK6l*&_x0l?39a*<=(}5;5tOMTwEEDZOU`*d11%;K}K-9?B=VPt=<utDeo8hJEFu> z*P2ML?BpTNh~!TPMY<Suu<Np_LiRT!!Qni$I}+Fw#T2>+BH^@6-mhSTf4}ia)axj4 z`{YC3*(f5nR}`hLLH&d0cTBSZPOY|@Ey|IQ=o-9CV3+uA$pGih983U@X_f5?boyBh z>Ca4BE@|uRvy0~=*NkDWQDw5wgu|0x!65tPf`uwfsCq3O`Q7=iJ!PtMb`i(+Kte0s zvHJ%wUNeUbI5=MYIgY_c<jVTniIDWC6aATB(ecpFm^uFu(y6QCr#i+ZRfPeZR)?j} z1|j^kl!>kl&g{@;!lcL8l1;eC5D_WoPtwpv;U{#zvne#E?|nURl5oj1I|R+yBA6&K z0CB;sHNnxM!2J-4Nw6-z^q~-jBmjF{kMoqYzO0{SggyjT2M=1MJjBv#IPp2og6T$@ z;ZTb-jyT|CtV*>J0HBK*f6MB{l}w0nY>!9qSeB!>pK%+60>qy)@;PQ}hOI}Z;=Y|f zmJ<qtj6482V#0+`>*kUoPck@{R!F3}Fv+#GOWI-8P87B+!%q&r93D`T3ejKB0_V%= zJQOo3C1+(`g#1mTaxTiqxxi-VOzkOfxs!8+s2gv~Ukuolv=;1U&%MGp7v~qiwD(>X zFpfV;*!)2@F1OB-cvUO*2V_iyTg~Uf5jjj{yKBZfZAsl4VjE@x5^6f^Q8R_?P6_;J z`Fr$Ora1DjZk&FY4Wf2qOUYcO&M9TCT(Ap9h7OGWY)#IGs7`_or>&EXqsJ!i`1>ZW z_SPt!BxyBc(|9WEQ6g`JJiL6PvbBFuCeKU8OIvPUJ_<?dJaowjXKzF2OP}9I>b1<; zth1dkOW}&VmU3%@0h9%mmd0FoZDvogSU*DCgUM)j{OKlM4h@R!c1e#=L@9NTKZnOU zDH|dBD7Iaw$K)8ozJ2|em!Z%i_~5UE3M^ejWup}v4ax%bw>}~=p98e^-&ap|#Ci<= z=IRbL7qlo1sCdPOdI}r!Ke&E_P5u#xTp0I^J<wxg<F?eGW;Ow+7>>i7Ly%C@r~d5D z7=^X=S{FQGH3sXFhORYA>+S>!iwNEmUAJPJ3~Z!ka78uMH8SeIg@dV#cduU5@S3_R z8*GUqTh(Vxxe_1X;LAO~RN@)^5bk2SC{qYSigDG1#GzXNHHY3uWX$*6sp;+I(?p{- zXIO;jNIHmAW5ee6?-cTLE<<RuhE1%<{`u2JE%uTs?yMU3n+{TlHiWkW4w<pRWbO5s zO;gOB8W%j9-MXGHa!w{ERI?{V12v7>r1H4Jx};+N*0tCflfSBV&&J*V$9F5&!@n=C zi61TNSjoRH-9&%%Mi2Yq!dmPfTHWs0Oar+`?94@!sj`o{@8pBv*IxRa!yQr#EZ5gr zh)i`$HZB=C#eZCJlVHL=8>zo74JlBp<f6UbB1_A<5Adt%z6$wZ|IqrXMCZXPN6b)W zvPAg?IZIn&)Ac7Z!xhPfL4z1a7ZPHD+@6t0z+&vvl$8(h2ai_+F3sd9<;FZJXQ^c6 zP$HslK$X0ziYhE5U8#7%I$5%(iV}1dIvZSECZc8TG$E~Yh;|K1v7O!IrT5qFAkxXy OukeR7XX$7Vn*Rkt>bd0r literal 11781 zcmb`Md$1%`ea8>-UY2OUXoQ6HBFpZ|&g_HdUY5sYUtHORW%usNBLsS8dS;s2(>?U# zUhWENB)&*Mjjq86M8Y3nQd%We3`&fNOJb#@5=s-xKt(GABS}$_ltRisLh|{Zb9!d> zVMtPT-80`lr_bYee&_c(zx&-&j@fT`9-{mb<*Z|k`5w4>2|qlKo@~r7fS&=Ef?xIc z6!>%0|K8VM0FS2rGPn->33wcM4xKdBdhitR5^yuP6I>4N2RDFEfG2`4gRckw3w#s! zdMaJ;Z17jWdqB<eSy1c!8K`xh1djo~0looz+PD8B$d=3t{`<fA`j0^V%uo1%RC6MO zP6OWzo(HZ6r@$Vl{r|rI{y6wL>fZu2?%Uvl;PasPbJx!sa}oFvP;~tjcs%$tC_a1# zJOTVCQ2TumybpW@)Vd#LbEkq&f|~C;;OXG^LGAA-KE4q=4txuEI;eHd2QLISf;WOC zsQI4;-wHkhYW%C9=sB86)`BO2w}2Z#oy!B@`@rYG)nK2^uLJjkP4Mer8+-*^58l8b zoeSOr{v!D2py+xA6#YL2w}D5!*_hkG8E^*t8u-iLQU*!x-Uf=!ZJ_9z1GTRLJPF(f zGL?BhsPlXPRKJHo@%0Zu@%4+K*8M7|^LYwXzh`{?Igc-a;?Jx8`w0-O{%-)qr!zpU z`&M6H<MBLD>u>P&%RtSu+2hq7uLISu<*^THKPjknDp2F@0!9Blpy<C36#Wl@qT_QO zzW}P=;~o!y;>TZuu+n@V6utimB8uijgjwsH25O#_;L%_M)H>@xtuy7nZv#c|c2IQg z^7ZRM^}iWJBupRF{CE2Ly`c8-FsS)H3yO{}`}$w{`nN#M`#n(o{~6SJFM&FrS3s@v zDkyr7N9fhQ6jZ-Af*OAssPD@_^*`I!*MRDG9;o@JK+(Gy#FUupLDAO-HNFC+$NNBy zyAu?D?*g^Xy&x)S_Jf_HjClmqd`l5p&9e+dB~265IZT5(hwDJiHv~6>^PuK?0u)_e z1KFZ^3Y-Cd07}2song$iU>nrA{Shd-4}i<SZ-RG#KL*bRZ^IbMe%%L(508SH|MR~7 z1c+#xCqb?M51{CJ9@PH-)z^OrivE{Dt+zBVhCg#UKbL|V!D;ZFAf%eFfXl&WLGkY> zh!efXfRBNvfa1?zfWHcU6V&=^&UEx$0E*trJ<fRC1^xl;H-h5ZaTo*f^D0pDx52Z( z+d#?1CqU8jAb1Y=C%*j!aGLr{U<s~gkmT_ZQ1<H!p!o0{sCixhr@)uM3_OR;?EpUo z-Ut2*cpms(n7#r0WAI||-@!$&vBKHEM?mrGSy1-uw3Uv&3qjGp2b=@j;77r~0cXK* zm81WQAX_)jfos5H-{$yszQ>KA___(ydF}M=Jy82dL7o4+$M=Ae-@85D@7q5Iim#9R z_NRUObD+-YMc@7-@EGdH!d&rh38?y;z!SjJLG?e&x1R%Q{k0%2#!P{t_i9l5zR_a{ zYJ3lrybVE(dpCFz_#sg9?gyoB_k-&Hc~J9x85BRi4r+gY2O_%W2Of`K?b=s>vQryC z^?y4k`mX~;&rRS-U>jTtW}w!+!{c3`*1a24|Br#9^ON9d;KLv;(EKSVe*P`E1bh+H zdjH|^*oLd03W}a(pypZcaU-a8w}Lvy9Uk|9qW30HbhJSAoAa3a?~DHXyFk(T0ss9T zQ2hNkh)XaJgC~Pu0Y&FGK+XSc@O9v`pvHgKe}CTBe+bIXybK-%o<-5KlJcAO&6r;U zucO>b=}|(;{S-vVyp!??$~BZvQ?94%py=67xsvi;%7CJ0fr9GVGyMptwU<+*YkIa& z-lG>D@llWVgLyXhQl$IRSLyUJ%KIp{Q9eakN2w?}uNGxDrG9q$mzzAwwr3RCFg=nL zJ-<bf-o9Uzi6`Y97FnCF=F9ZMGf#QDeRJ_o&b#cy(6_zIV+=m%-!BLEQY7Dcew$KK z<|sE%^nAd9l^MP2to2+%xtbzd(xvE;++9HV808^~?Aiv(KFVDb+0l<u^xWgX#*!=i zyP)siKkTvaC^(z)A<7w)jg)IC(h)sPisV<%(GE=FaS}RI&Zpc=kzDHeB<1%gvIBY| z2ljWBf8RRMrq}(HZ4}wy$tR$)o^q~lL_Mt?eG9mWvYGNhigfx8ik{!0NH>n9tfjo0 zvXt@w<sFnZ<ra$kte%S~r&4aD{5s|1lq)Ec&u>t<+c)e1&++dUgTG6;ld^`gi*g+0 zD$2<e6I`(vEMM7;lQPP0F5@zZRuzF+nPx#d9F}pGt}@e|4qei4z$aU2_v54!48vYz zt7)_l#AP%v(@CNdw6nB~(lUsPAWr*H&c{yB&9gyJ_G#0=Anpdecs@#-=88BC^F^~M zZ1?H5XV-RK(=;oCPLxC?JvH^=O{;@e)DEjc9kkLg%(Z6L4Z<==qOjmSje@L%06Rys zo@5ZtML`&(Sx4YD!?3t4qNF?Ol}CeYK5`Uyb2c9=ux(aLi<p6SCt+t0r$G_5#VAJh z!<4NpFX}faA0}ZLnN3;RjdS*&9lR^gD9@Xy-bBHkwWqKuvq4zK?J!9e$GmI?vsnOf zc|M|~74^gUIIHs2LCA3x8T9&NfUZ1(h@c;LI#EjVa8Ya;okjh<%)_*RT=rr%Ri)W% z`ERy#;?n*ElO48Ni7{J~u;`mBS<cK1BoH%c5#?nN7LKuXy%lw{oUd@ia{wZ%b~`GH zZpG%BW_uLEZWvawQ&C4HE%U{o=w}t;R+Qml5W;DCX)d;353)OPBl%*7#gSys&N9s7 z0Rk2z98M+CTe-Yg)igVFx|}$NhuBHTI306!=3e`3pcTQbx<}JobCtQq3R7nFqA=Ht zPXKuc^IlX+e4D`)OkCx(F<IJ9D#Qi87JX<!Hnp=>)Qi(JPJ2O^cIw86S9b2iISi7F zV|NqIN^Qb!7g`|;k+zehoOsV3mz|}kTGFgyg~k+3vvc#-pp&($0c<oowQ;N7VqVb7 zvjxs6Scub3w$KcAOTO8%>(N@|jJjc!l+0q)%It*UakKztL(UiWnq9kh2i+*@j9zGp ztf01?9@Nr*S+KE{2Wu|1ronz<Gq9)Nz}Y;zt__COgN;R*XKC-!<tq#1xgFh{!>lYV zRuvo9_)pReX=g_)9`|==;QLQ>Z~lJ>8x5K;Lzgj;XmMgn1?_H2Yo+xo%Z#OM3wClh zo3lUegwe?mn}#hKH)_{$S|R6X7_wk?M`7OX0}@L5J5gjgiA)l8%fOl*WMna`f`t%s z$Nn{%p3QokIuEi=g{>Oq*?ioQnAO5zPk*HO5;skia*Ud)T@@Idc%RH$6pZDIx%*jO zwyUx*vm-&bbB#<?kV8l=32mC$==Rdga@2FhGEmHM?jtyJ`O2(y>#E{R$d`$b!93Iw zXn>W7+sgpqt+3;ko-&W3AkXj&k{Mf*4afA`ZAOkOG1`F%grixC{=f-(VD2QhR#_mA z1u(~Wh$O~EAWYisAe6z72V8CI-7HBm6r^W+d6BJJwukn}ki00ED8f21M>XtVW!a2O z6DybTKnfpp!o_AV?e|(6C8uZ$G2SvuvF)uWn2(FN#i9A#_GQAYWQARPvpW&^YIV*p zCMsANeYf5s!OnLUF-3D2E|eGv@&;4$yk=+TDi0r_y%lUshC__%MX6Xx%UD8?p3E=c z?KL~XhQ;Ze1S{0plof5vF%M%hemhaNI*6N5b1LYU<#1}vnuUdhrtjEnXM;5hVcG6q zHh;;!!L94^;l9ngZdmJfY#GOFLlh3P2`MZh+PvKYi*_DcL+#0W%^`Eq;zE{ppt(Sq zW+iOSLLKa<_KI#7%~a`Jnk}Tk5Zwq9vlj!Y)06i$@6gdgVS!T^>4>$CS&GS!*5TJ- z4n*HFtXix}_;U+l61C@A+3i8t!oW4n^>l1=khM*vJ4Uc-mvS)Hi=(WfRYp4xdyNhj zdMK&IipcaA&0wd(A@n&T2q^owAU9co`S(OxOB@dds4xeMI}Yr^#1sg*vuVVDOeJy# zIO0QXm)!@<XiSI?+ed-i7BohIi8q4Gb?8@b#)7aXJv?Nn{U}xuyu_Tg)eGN8E8-rE zTiJxeVM4%UqnL0$jFV7GH4(ZLriE*rGd{ir%cz&-a%ui`(P(?jCy^f<RH2WH*=lqa zV_aJtY92zYJnr>N)3%{k$DurjY=q$_G!r6faKfq4CQXDHN(}LMWPh+1-ORle*k$)t zvWR^v451A{m;I%ZPG}@GA9@=U*c%s92SL1G{=CUD@-0TXY6ju$P3v|FV}&8Gl#E{| z89C8ovUzf(-b+m2SQ}k~*R{gPEf_8k2F>H5fD=UOU0kc1fX><e6#Oc_H~7~$HNy-g zgPjHg(4d{MNJV`#R-K#(IDStyD9W;jFj6`*dP93n9xjX~ns_fv?cXppyes@LdE6!x zle2TD?Qa6cV_}M<>KT0Rt@uS#N)p{~0rdE(?+11c>l2Lg48&*SH|y`(SyByBGa<;R z|74ZvBp21tSkvl$tp#?k1>ii44YL~B2jQGZYs_>Sd!xL7qf^1o=}lKnZ`%^=-Lh-< z%r#dpA<DtNHFgxexYM|z>J^RIY${l?^P1U)y;v})u^FkJ3f8Y(yP>geZDZYq!MgQR z=U#BmT3YDX*hTQD$q(<he*M(C^OtN#7#p+x`jO>R!H%#bNFhSFDk`{2_OoPPuyHVV zc{h?&6YRA6momx)^o`jl983k<r?1|&M}%+OzWwqfZf1G!(j_})c5E4MZC!Kil1)y3 z8?!KL${yYtD^nNCD(0B$OZLoeZCo_&C$hRx-q@11GsRL<!9}gOTyour;HcBsQ`irk zTOlcH<QdZ-_G_ExH7{IZHixfy!|wIsD(%JNILS=cO{f4DWc09?#M!txt+IJyKWF1J zGh3A$r+(ug_VQctUS!<lr5tg|5h3`&Z51pHWkH#CHU3GLMXs@UJ)C-Y@O@mN1s6Ni z4aw2%H%emqqKd(M*4CZxr+r!-5O1~n2R;)VcodJ(VMHem!UUI;1r>owLX<zEzsbc5 zKUy7lEa+--IuP1%S&sGE3J0y2Vbnx!$)%BCV{&b-c<_UL*4t}mc^bEg<m3Wr#`CU- z$x7sI8qb6x+J{u~RrmO&*&F6@Xj_&C+~KuqXah(BL9?Ay0k`-lA7IbK*r6_#S~3Y8 zGn{0J>m9;B3{(b}wQ+7vT4Z#Y7frCTJ{24^@m<_Yvs`<(v=NJE@Rqnjor#k|Cl6W= zjtsM41w=T5$BOQb&o}u;QX65>&UDK3Iq1CYRbR%sQ`vnI%_CN<YPQq|%f+}8ck!U3 z7p7&46N7a3&oh7b-xL<%<lR3m+9HhL)gPNn0dO@STEkJXl8sAr_*Ry5?@-j_vH=_{ z)}Sq#g83@rBS-Ez%yo7?k6J`knus72rXuj@0kTHF0p8%S;Wax$*lGJA#mFvdlFB%e z5^!{J^kfDCr3Q8*)G#kuQL7hoCstHKr3er|j$rf+`KGrebkxaa3#Q=`G1^d^j?GMc zzR3#3>zoW;k!zn5IBp22Si8~{Mc;hhfbo#q3Uh7Mig3(qfvw0UAXd_dSf?Y4!$?Te z{5E?KHG^xV?imbYqdDqduua(MB6lkT%!UluK}CiYv6dkURveN+m_?owo4#VWH%ekV zHPIpK!H$S|U21`xg4I*SM;fQDv8+YuHmuN{U>&<7o8z+#)98g0l9|CE!{EfD<bv6% zJ1RK`%;`LuuKc9*6UOL@hlbW^hCo)(@{JFYWWq)gjXhbyB24CG2f6gsX-c$mltO?% zhi4svaoRygZMQHnhI_xg5g#e-@G~G4%?`ORB+1A$IBQd<BAk|lW;dLT%SviCKA(eg z5&@|PwvV!VlpGyoR;*E;_$vEChC)k+#O_0DkQ~PyW6ds%Y>ur^&O*`@B7crR6gq(v z>4kGH7%?ZS$US!`#KoUam?vocXa?rzaQIdsHaa|laJ&<jrb+RXJRM}(?CjiEINerU zWN4eTfo{0KFp2l=(=HB{d=|w|U~9@Oj?59X(n;+ovoSW|&^s%=GTU;*Ia+3BlCkd& z&g9)@Id~gchkCOx<Y05hP;7i9YOOtI+SMWyBMoz<Q^|@jX-VXDhohUC&}6QGCD*`^ zIIx@R;7QmKLvxi8_t<lJ;M1D5Tc!4BtS6CubOuk>FA7B<?5?$x5WF1^L*+m)JVn&2 za6hrkhc2E{A-O)RgdKq2fqE1X)2dvEcXY@UN2a46#s|KHwS_Ls7YTowvu3ad5vkc> zZH8aH2y-a5QL18%LUscyJ<f!5G8Teb5<XbV0eJ<#l-(Lrv2!9Y+)C4U!>3bai@lhc zoteh)6v&2?RBy<v8^I3!Zw7G~vUNuu={SH#wh|`}I1@Q(Z+-rRgoUo^h>~A*<lS&E z-p||o395%tw?Vy*lPmbF&7`QZSGknc!8|9XR1;G0e@dqKl^x^BClcz*Ti|MB%#}iM zF2V|(&j|n2F>;B-$Rdl&S_Vb@Z$%k|v8l&BPdia|miSOzaLE;gPcEl|5TFwo@c=9} zdkJH$Sy607Etj}>ry{Bk39y_cN^py^B66bM1hmP9*d02JgH#0VmRpEFTjXK5I9joT z>NYMa-G^Kp_#gz;F>o!q&Yq0ba8gsH;zvx!#5hLyLr&XzYjQFoN(90$KQk3P9QTe1 zk5wmUY&-}XuMDM#&gMg}ax<E@I`EjaBDK}7r}R7bLQA0OA}1ixd0Cal9QqlK;1!gy zIbz=lZZMI%mK-wOL>J`B(_kZ2D8H>5EpH=(*f?dZ6FF7@%_#a*bc7F1bsdRqCa0Z| zx3QVNI)8&Puai2VQ3}W2J!D*&nrzBpE!OU)h>sbYLQd1!W7}TFLmQWkdmfVG$&8XZ z;-ykPj%Zq9GoeNXEA%B(bHhZ9BjtKJXf*#~)U`w;*!&BtTeTXcg~o{=@;|s&l0B0l zovH5@nZfqe2GzK5*X&71O&?-Ajd#+aA<vK?oYtbcbWq6uduWY~mJbGa8Av2isAR_I zCZV1G58o~G4*z~=OZ=MoBK@b)3YjuSb@Y5#(ufbn%2{Nvwpa^-9+x@VN#@9%4m#*l zN8AGJ!P(4!3{8EMwLusir;oW0Zm(;I&-fKLHIYivq~m0gt&z#VTq`bdtR7uq$tBfU zCEXD6(D-Yr$Jl3;vL63%WX&?f!Fq@f%PT2JnYAIf@<}#=w+9unj7$(B=G%37OtKWt c9dxSW8j~Z3q_fPC6HGMwECJ575rpQy0nSLj9{>OV diff --git a/feincms/locale/it/LC_MESSAGES/django.po b/feincms/locale/it/LC_MESSAGES/django.po index 73919853d..b38dbc4b7 100644 --- a/feincms/locale/it/LC_MESSAGES/django.po +++ b/feincms/locale/it/LC_MESSAGES/django.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" -"Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" +"POT-Creation-Date: 2012-08-11 13:53+0200\n" +"PO-Revision-Date: 2012-08-14 17:41+0100\n" +"Last-Translator: Paolo Dina\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: it\n" "MIME-Version: 1.0\n" @@ -19,11 +19,11 @@ msgstr "" #: models.py:420 content/template/models.py:59 msgid "template" -msgstr "template" +msgstr "tipo pagina" #: models.py:551 msgid "ordering" -msgstr "ordinazione" +msgstr "ordine" #: translations.py:259 module/blog/extensions/translations.py:17 #: module/extensions/translations.py:119 @@ -36,17 +36,17 @@ msgstr "Tutto" #: admin/filterspecs.py:46 module/page/models.py:143 msgid "Parent" -msgstr "Parent" +msgstr "Genitore" #: admin/filterspecs.py:81 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" -msgstr "" +msgstr "categoria" #: admin/item_editor.py:157 #, python-format msgid "Change %s" -msgstr "Variazione% s" +msgstr "Modifica% s" #: admin/tree_editor.py:229 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 @@ -58,11 +58,11 @@ msgstr "Titolo" #: admin/tree_editor.py:404 #, python-format msgid "%s has been moved to a new position." -msgstr "" +msgstr "%s è stato spostato in una nuova posizione. " #: admin/tree_editor.py:408 msgid "Did not understand moving instruction." -msgstr "" +msgstr "Istruzione di spostamento non riconosciuta" #: admin/tree_editor.py:417 msgid "actions" @@ -71,20 +71,20 @@ msgstr "azioni" #: admin/tree_editor.py:429 #, fuzzy, python-format msgid "Successfully deleted %s items." -msgstr "Cancellare questa voce?" +msgstr "Cancellati con successo %s elementi." #: admin/tree_editor.py:437 #, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "" +msgstr "Elimina %(verbose_name_plural)s elementi" #: content/application/models.py:272 msgid "application content" -msgstr "" +msgstr "contenuto applicazione" #: content/application/models.py:273 msgid "application contents" -msgstr "" +msgstr "contenuti applicazione" #: content/application/models.py:298 msgid "application" @@ -92,23 +92,23 @@ msgstr "applicazione" #: content/comments/models.py:24 msgid "enabled" -msgstr "" +msgstr "tavolo" #: content/comments/models.py:24 msgid "New comments may be added" -msgstr "" +msgstr "E' possibile aggiungere nuovi commenti" #: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" -msgstr "" +msgstr "contenuto" #: content/comments/models.py:49 msgid "public" -msgstr "" +msgstr "pubblicato" #: content/comments/models.py:49 msgid "not public" -msgstr "" +msgstr "non pubblico" #: content/contactform/models.py:18 msgid "name" @@ -122,17 +122,18 @@ msgstr "e-mail" msgid "subject" msgstr "soggetto" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:23 +#: content/raw/models.py:14 msgid "content" msgstr "contenuto" #: content/contactform/models.py:34 msgid "contact form" -msgstr "forme di contatto" +msgstr "modulo di contatto" #: content/contactform/models.py:35 msgid "contact forms" -msgstr "forme di contatto" +msgstr "moduli di contatto" #: content/file/models.py:20 content/file/models.py:25 #: module/medialibrary/models.py:84 @@ -149,15 +150,16 @@ msgstr "image" #: content/image/models.py:46 msgid "alternate text" -msgstr "" +msgstr "alternativa testuale" #: content/image/models.py:47 msgid "Description of image" -msgstr "" +msgstr "descrizione" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:48 +#: module/medialibrary/models.py:233 msgid "caption" -msgstr "caption" +msgstr "didascalia" #: content/image/models.py:53 msgid "images" @@ -174,7 +176,7 @@ msgstr "" #: content/medialibrary/models.py:48 msgid "(no caption)" -msgstr "(no caption)" +msgstr "(no didascalia)" #: content/medialibrary/models.py:97 content/medialibrary/models.py:111 #: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 @@ -219,14 +221,12 @@ msgstr "" #: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" -msgstr "" +msgstr "Ignora gli avvisi di validazione HTML" #: content/richtext/models.py:47 #, python-format -msgid "" -"HTML validation produced %(count)d warnings. Please review the updated " -"content below before continuing: %(messages)s" -msgstr "" +msgid "HTML validation produced %(count)d warnings. Please review the updated content below before continuing: %(messages)s" +msgstr "La validazione HTML ha prodotto %(count)d avvisi. Prima di continuarerivedi il contenuto aggiornato sotto: %(messages)s" #: content/richtext/models.py:81 content/section/models.py:35 msgid "text" @@ -241,12 +241,8 @@ msgid "rich texts" msgstr "" #: content/rss/models.py:21 -msgid "" -"The rss field is updated several times a day. A change in the title will " -"only be visible on the home page after the next feed update." -msgstr "" -"Il campo rss viene aggiornato più volte al giorno. Una modifica del titolo " -"sarà visibile solo in home page dopo il prossimo aggiornamento dei mangimi." +msgid "The rss field is updated several times a day. A change in the title will only be visible on the home page after the next feed update." +msgstr "Il campo rss viene aggiornato più volte al giorno. Una modifica del titolo sarà visibile in home page solo dopo il successivo aggiornamento del feed." #: content/rss/models.py:22 msgid "link" @@ -262,11 +258,11 @@ msgstr "Ultimo aggiornamento" #: content/rss/models.py:25 msgid "max. items" -msgstr "max. articoli" +msgstr "max. elementi" #: content/rss/models.py:29 msgid "RSS feed" -msgstr "RSS feed" +msgstr "Feed RSS" #: content/rss/models.py:30 msgid "RSS feeds" @@ -286,7 +282,7 @@ msgstr "plain" #: content/table/models.py:67 msgid "title row" -msgstr "titolo di fila" +msgstr "riga del titolo" #: content/table/models.py:69 msgid "title row and column" @@ -294,11 +290,11 @@ msgstr "riga del titolo e colonna" #: content/table/models.py:75 msgid "table" -msgstr "tavolo" +msgstr "tabella" #: content/table/models.py:76 msgid "tables" -msgstr "tavoli" +msgstr "tabelle" #: content/table/models.py:90 msgid "data" @@ -306,11 +302,11 @@ msgstr "dati" #: content/template/models.py:51 msgid "template content" -msgstr "" +msgstr "contenuto pagina" #: content/template/models.py:52 msgid "template contents" -msgstr "" +msgstr "contenuti pagina" #: content/video/models.py:25 msgid "video link" @@ -342,7 +338,7 @@ msgstr "pubblicato" #: module/blog/models.py:30 msgid "This is used for the generated navigation too." -msgstr "Questo viene utilizzato per la navigazione generato troppo." +msgstr "E' anche usato per generare il sistema di navigazione." #: module/blog/models.py:33 msgid "published on" @@ -350,9 +346,7 @@ msgstr "pubblicato il" #: module/blog/models.py:34 msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Verrà impostato automaticamente una volta che barrare la casella di " -"controllo `` pubblicato in precedenza." +msgstr "Verrà impostato automaticamente una volta che spunti la casella di controllo `` pubblicato in precedenza." #: module/blog/models.py:39 msgid "entry" @@ -374,7 +368,7 @@ msgstr "traduzione di" #: module/blog/extensions/translations.py:23 #: module/extensions/translations.py:125 msgid "Leave this empty for entries in the primary language." -msgstr "" +msgstr "Lasciare vuoto questo campo per le voci in lingua primaria (% s)." #: module/blog/extensions/translations.py:44 #: templates/admin/feincms/item_editor.html:43 @@ -387,7 +381,7 @@ msgstr "data di creazione" #: module/extensions/changedate.py:33 msgid "modification date" -msgstr "" +msgstr "data di modifica" #: module/extensions/ct_tracker.py:136 msgid "content types" @@ -395,7 +389,7 @@ msgstr "tipi di contenuto" #: module/extensions/datepublisher.py:49 msgid "publication date" -msgstr "data di pubblicazione" +msgstr "data inizio pubblicazione" #: module/extensions/datepublisher.py:51 msgid "publication end date" @@ -403,7 +397,7 @@ msgstr "data fine pubblicazione" #: module/extensions/datepublisher.py:53 msgid "Leave empty if the entry should stay active forever." -msgstr "Lasciare vuoto se la voce dovrebbe rimanere attivo per sempre." +msgstr "Non specificare data e ora se la pagina deve rimanere attiva per sempre." #: module/extensions/datepublisher.py:80 msgid "visible from - to" @@ -411,15 +405,15 @@ msgstr "visibile da - a" #: module/extensions/datepublisher.py:90 msgid "Date-based publishing" -msgstr "" +msgstr "Date di pubblicazione" #: module/extensions/featured.py:9 msgid "featured" -msgstr "" +msgstr "in evidenza" #: module/extensions/featured.py:14 msgid "Featured" -msgstr "" +msgstr "In evidenza" #: module/extensions/seo.py:9 msgid "meta keywords" @@ -427,7 +421,7 @@ msgstr "meta keywords" #: module/extensions/seo.py:10 msgid "This will be prepended to the default keyword list." -msgstr "Questo sarà anteposto al elenco di parole chiave predefinite." +msgstr "Questo sarà anteposto all'elenco di parole chiave predefinite." #: module/extensions/seo.py:11 msgid "meta description" @@ -435,33 +429,19 @@ msgstr "meta description" #: module/extensions/seo.py:12 msgid "This will be prepended to the default description." -msgstr "Questo sarà anteposto alla descrizione di default." +msgstr "Questo sarà anteposto alla descrizione predefinita." #: module/extensions/seo.py:18 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:192 -msgid "Edit translation" -msgstr "Modificare la traduzione" - -#: module/extensions/translations.py:195 -msgid "Create translation" -msgstr "Crea traduzione" - -#: module/extensions/translations.py:200 -msgid "translations" -msgstr "traduzioni" - #: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" msgstr "" #: module/medialibrary/forms.py:64 #, python-format -msgid "" -"Cannot overwrite with different file type (attempt to overwrite a " -"%(old_ext)s with a %(new_ext)s)" +msgid "Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)" msgstr "" #: module/medialibrary/modeladmins.py:57 @@ -476,14 +456,12 @@ msgid "Add selected media files to category" msgstr "" #: module/medialibrary/modeladmins.py:84 -#, python-format msgid "ZIP file exported as %s" -msgstr "" +msgstr "File ZIP non valido: %s" #: module/medialibrary/modeladmins.py:86 -#, python-format msgid "ZIP file export failed: %s" -msgstr "" +msgstr "File ZIP non valido: %s" #: module/medialibrary/modeladmins.py:91 msgid "Export selected media files as zip file" @@ -494,15 +472,18 @@ msgstr "" msgid "Preview" msgstr "Anteprima" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:139 +#: module/medialibrary/models.py:87 msgid "file size" msgstr "dimensione del file" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:144 +#: module/medialibrary/models.py:85 msgid "created" msgstr "creato" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:163 +#: module/medialibrary/models.py:84 msgid "file type" msgstr "tipo di file" @@ -513,16 +494,15 @@ msgstr "file info" #: module/medialibrary/modeladmins.py:196 #, python-format msgid "%d files imported" -msgstr "" +msgstr "%d file importati" #: module/medialibrary/modeladmins.py:198 -#, python-format msgid "ZIP import failed: %s" -msgstr "" +msgstr "File ZIP non valido: %s" #: module/medialibrary/modeladmins.py:200 msgid "No input file given" -msgstr "" +msgstr "File in input non specificato" #: module/medialibrary/models.py:43 msgid "parent" @@ -546,11 +526,11 @@ msgstr "copyright" #: module/medialibrary/models.py:202 msgid "Image" -msgstr "Image" +msgstr "Immagine" #: module/medialibrary/models.py:203 msgid "Video" -msgstr "" +msgstr "video" #: module/medialibrary/models.py:204 msgid "Audio" @@ -558,7 +538,7 @@ msgstr "" #: module/medialibrary/models.py:205 msgid "PDF document" -msgstr "PDF document" +msgstr "Documento PDF" #: module/medialibrary/models.py:206 msgid "Flash" @@ -570,11 +550,11 @@ msgstr "Testo" #: module/medialibrary/models.py:208 msgid "Rich Text" -msgstr "" +msgstr "rich text" #: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "" +msgstr "Archivio Zip" #: module/medialibrary/models.py:210 msgid "Microsoft Word" @@ -590,7 +570,7 @@ msgstr "" #: module/medialibrary/models.py:213 msgid "Binary" -msgstr "Binary" +msgstr "Binario" #: module/medialibrary/models.py:236 msgid "description" @@ -606,11 +586,11 @@ msgstr "traduzioni di file multimediale" #: module/page/forms.py:118 msgid "This URL is already taken by an active page." -msgstr "Questo URL è già stato preso da una pagina attiva." +msgstr "Questo URL è già usato da una pagina attiva." #: module/page/forms.py:136 msgid "This URL is already taken by another active page." -msgstr "Questo URL è già stato preso da un'altra pagina attiva." +msgstr "Questo URL è già usato da un'altra pagina attiva." #: module/page/modeladmins.py:41 msgid "Other options" @@ -622,7 +602,7 @@ msgstr "in navigazione" #: module/page/modeladmins.py:100 msgid "Add child page" -msgstr "Aggiungi pagina figlio" +msgstr "Aggiungi sottopagina" #: module/page/modeladmins.py:102 #: templates/admin/feincms/content_inline.html:9 @@ -637,7 +617,7 @@ msgstr "" #: module/page/modeladmins.py:144 msgid "You don't have the necessary permissions to edit this object" -msgstr "" +msgstr "Non possiedi i permessi necessari per modificare questo oggetto" #: module/page/modeladmins.py:159 msgid "inherited" @@ -645,37 +625,38 @@ msgstr "ereditato" #: module/page/modeladmins.py:163 msgid "extensions" -msgstr "" +msgstr "estensioni" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:167 +#: module/page/models.py:179 msgid "is active" -msgstr "" +msgstr "attivo" #: module/page/models.py:138 msgid "active" -msgstr "attiva" +msgstr "attivo" #: module/page/models.py:146 msgid "override URL" -msgstr "override URL" +msgstr "sovrascrivi URL" -#: module/page/models.py:147 +#: module/page/models.py:265 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -"Ignorare l'URL di destinazione. Assicurati di includere le barre all'inizio " +"Sovrascrivere l'URL di destinazione. Assicurati di includere le barre all'inizio " "e alla fine se si tratta di un URL locale. Questo riguarda sia la " "navigazione e gli URL sottopagine '." #: module/page/models.py:148 msgid "redirect to" -msgstr "reindirizzamento" +msgstr "redirect" #: module/page/models.py:149 msgid "Target URL for automatic redirects." -msgstr "URL di destinazione per i redirect automatico." +msgstr "URL di destinazione per i redirect automatici." #: module/page/models.py:150 msgid "Cached URL" @@ -704,23 +685,19 @@ msgstr "" #: module/page/extensions/navigation.py:80 #: module/page/extensions/navigation.py:100 msgid "navigation extension" -msgstr "" +msgstr "estensione di navigazione" #: module/page/extensions/navigation.py:102 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "" -"Selezionare il modulo che fornisce sottopagine per questa pagina, se avete " -"bisogno di personalizzare la navigazione." +msgid "Select the module providing subpages for this page if you need to customize the navigation." +msgstr "Selezionare il modulo che fornisce sottopagine per questa pagina, se avete bisogno di personalizzare la navigazione." #: module/page/extensions/navigation.py:115 msgid "Navigation extension" -msgstr "" +msgstr "estensione di navigazione" #: module/page/extensions/relatedpages.py:13 msgid "Select pages that should be listed as related content." -msgstr "" +msgstr "Seleziona le pagine da elencare come in relazione a questa pagina." #: module/page/extensions/relatedpages.py:20 msgid "Related pages" @@ -728,38 +705,47 @@ msgstr "" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Sito" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" -msgstr "" +msgstr "pagina collegata" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "Tutti i contenuti sono ereditate da questa pagina, se somministrata." +msgstr "Tutti i contenuti sono ereditati da questa pagina, se specificata." #: module/page/extensions/titles.py:13 msgid "content title" -msgstr "il titolo del contenuto" +msgstr "titolo del contenuto" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" -"La prima linea è il titolo principale, le seguenti righe sono i sottotitoli." +msgstr "La prima riga rappresenta il titolo principale, le righe seguenti i sottotitoli." #: module/page/extensions/titles.py:15 msgid "page title" -msgstr "" +msgstr "titolo della pagina" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Titolo della pagina per la finestra del browser. Stesso titolo per " -"impostazione predefinita." +msgstr "Titolo della pagina per la finestra del browser. Per impostazione predefinita assume lo stesso valore del campo Titolo." #: module/page/extensions/titles.py:43 msgid "Titles" -msgstr "" +msgstr "Titoli" + +#: module/page/extensions/translations.py:171 +msgid "Edit translation" +msgstr "Modificare la traduzione" + +#: module/page/extensions/translations.py:174 +msgid "Create translation" +msgstr "Crea traduzione" + +#: module/page/extensions/translations.py:179 +msgid "translations" +msgstr "traduzioni" #: templates/admin/filter.html:3 #, python-format @@ -772,95 +758,91 @@ msgstr "Ricerca" #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" -msgstr "Cancellare questa voce?" +msgstr "Vuoi davvero eliminare questa voce?" #: templates/admin/feincms/_messages_js.html:4 msgid "Confirm to delete item" -msgstr "La conferma di sopprimere la voce" +msgstr "Conferma di eliminazione contenuto" #: templates/admin/feincms/_messages_js.html:5 msgid "Item deleted successfully." -msgstr "Elemento eliminato con successo." +msgstr "Contenuto eliminato con successo." #: templates/admin/feincms/_messages_js.html:5 msgid "Cannot delete item" -msgstr "Impossibile eliminare voce" +msgstr "Impossibile eliminare contenuto" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Impossibile eliminare voce, perché è madre di almeno un altro elemento." +msgstr "Impossibile eliminare elemento, perché è genitore di almeno un altro elemento." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" -msgstr "Cambia modello" +msgstr "Cambia tipo pagina" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." -msgstr "Davvero cambiare modello? <br /> Tutte le modifiche vengono salvate." +msgstr "Vuoi davvero cambiare tipo di pagina? <br /> Tutte le modifiche vengono salvate." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" -"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +"%(source_regions)s</strong> is moved to <strong>%(target_region)s</strong>." msgstr "" "Davvero cambiare modello? <br /> Tutte le modifiche vengono salvate e il " -"contenuto <strong>da %(source_regions)s </strong> è spostato <strong>" +"contenuto <strong>da %(source_regions)s </strong> è spostato <strong>" "%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" -msgstr "" +msgstr "Nascondi" #: templates/admin/feincms/_messages_js.html:13 msgid "Show" -msgstr "" +msgstr "Mostra" #: templates/admin/feincms/_messages_js.html:14 msgid "After" -msgstr "" +msgstr "Dopo" #: templates/admin/feincms/_messages_js.html:15 msgid "Before" -msgstr "" +msgstr "Prima" #: templates/admin/feincms/_messages_js.html:16 msgid "Insert new:" -msgstr "" +msgstr "Inserisci nuovo" +# TODO: nuova/o? #: templates/admin/feincms/content_editor.html:11 msgid "Region empty" msgstr "Regione vuota" #: templates/admin/feincms/content_editor.html:15 -msgid "" -"Content from the parent site is automatically inherited. To override this " -"behaviour, add some content." -msgstr "" -"Contenuti dal sito padre viene automaticamente ereditate. Per ignorare " -"questo comportamento, aggiungere un po 'di contenuti." +msgid "Content from the parent site is automatically inherited. To override this behaviour, add some content." +msgstr "Il contenuto della pagina genitore viene ereditato automaticamente. Per evitare che ciò accada Aggiungi nuovi contenuti." #: templates/admin/feincms/content_editor.html:23 msgid "Add new item" -msgstr "Aggiungi nuovo elemento" +msgstr "Aggiungi nuovo contenuto" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "" +msgstr "Aggiungi altro %(verbose_name)s" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" -msgstr "" +msgstr "Rimuovi" #: templates/admin/feincms/fe_editor.html:40 msgid "Save" -msgstr "Salvare" +msgstr "Salva" #: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" -msgstr "" +msgstr "Interrompi modifica" #: templates/admin/feincms/fe_tools.html:33 msgid "edit" @@ -876,40 +858,40 @@ msgstr "su" #: templates/admin/feincms/fe_tools.html:37 msgid "down" -msgstr "giù" +msgstr "giù" #: templates/admin/feincms/fe_tools.html:38 msgid "remove" -msgstr "rimuovere" +msgstr "rimuovi" #: templates/admin/feincms/recover_form.html:8 #: templates/admin/feincms/revision_form.html:8 #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" -msgstr "Casa" +msgstr "Pagina principale" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Ripristina cancellati %(verbose_name)s" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Premi il pulsante salva qua sotto per ripristinare questaversione dell'oggetto." #: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "" +msgstr "Storia" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Annulla modifiche %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Premi il pulsante salva qua sotto per annullare le modificheeffettuate a questa versione dell'oggetto." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -917,11 +899,11 @@ msgstr "Scorciatoie" #: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" -msgstr "" +msgstr "Chiudi albero" #: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" -msgstr "" +msgstr "Espandi albero" #: templates/admin/feincms/tree_editor.html:38 msgid "Filter" @@ -929,16 +911,16 @@ msgstr "Filtro" #: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" -msgstr "" +msgstr "Modifica sul sito" #: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "" +msgstr "Aggiungi" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "" +msgstr "Aggiungi file multimediali a categoria" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -946,54 +928,54 @@ msgstr "" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" +msgstr "I seguenti file multimediali saranno aggiunti a categoriaselezionata:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "" +msgstr "Aggiungi a categoria" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "Annulla" #: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" -msgstr "" +msgstr "Carica un file ZIP:" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "" +msgstr "Sovrascrivi" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" -msgstr "" +msgstr "Invia" #: templates/content/comments/default.html:10 #, python-format msgid "%(comment_count)s comments." -msgstr "" +msgstr "%(comment_count)s commenti." #: templates/content/comments/default.html:18 #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br /" -">\n" +" %(comment_username)s said on %(comment_submit_date)s<br />\n" " " msgstr "" #: templates/content/comments/default.html:28 msgid "No comments." -msgstr "" +msgstr "Nessun commento." #: templates/content/comments/default.html:36 msgid "Post Comment" -msgstr "" +msgstr "Pubblica commento" #: templates/content/contactform/form.html:9 msgid "Submit" -msgstr "" +msgstr "Invia" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Grazie!" + From b1d76106870cd2a39e19783f61313e44f9632392 Mon Sep 17 00:00:00 2001 From: Cellarosi Marco <cellarosi@gmail.com> Date: Wed, 28 Nov 2012 00:06:38 +0100 Subject: [PATCH 0573/1590] Added patch to frontend bug cookies check --- feincms/module/page/processors.py | 8 +++-- feincms/tests/page_tests.py | 51 +++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index d2d71ef88..20de6be1c 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -24,9 +24,10 @@ def redirect_request_processor(page, request): return HttpResponseRedirect(target) raise Http404() + def frontendediting_request_processor(page, request): """ - Sets the frontend editing state in the session depending on the + Sets the frontend editing state in the cookie depending on the ``frontend_editing`` GET parameter and the user's permissions. """ if not 'frontend_editing' in request.GET: @@ -39,7 +40,10 @@ def frontendediting_request_processor(page, request): except ValueError: enable_fe = False - response.set_cookie('frontend_editing', enable_fe) + if enable_fe: + response.set_cookie('frontend_editing', enable_fe) + else: + response.delete_cookie('frontend_editing') # Redirect to cleanup URLs return response diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 8dd36dd04..ae6d9ec23 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -32,6 +32,7 @@ from feincms.context_processors import add_page_if_missing from feincms.models import ContentProxy from feincms.module.medialibrary.models import Category, MediaFile +from feincms.module.page import processors from feincms.module.page.models import Page from feincms.templatetags import feincms_tags from feincms.translations import short_language_code @@ -589,12 +590,56 @@ def test_15_frontend_editing(self): self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') request = Empty() - request.COOKIES = {'frontend_editing': True} + request.COOKIES = {'frontend_editing': "True"} - self.assertTrue('class="fe_box"' in\ + self.assertIn('class="fe_box"', page.content.main[0].fe_render(request=request)) - self.assertFalse('class="fe_box"' in self.client.get(page.get_absolute_url() + '?frontend_editing=1').content) + def test_15_b_client_frontend_editing(self): + self.create_default_page_set() + page = Page.objects.get(pk=1) + self.create_pagecontent(page) + + page.active = True + page.template_key = 'theother' + page.save() + + # FEINCMS_FRONTEND_EDITING is False by default + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=1', + follow=True) + self.assertNotIn('class="fe_box"', response.content) + self.assertNotIn('frontend_editing', self.client.cookies) + + # manually register request processor + # override_settings(FEINCMS_FRONTEND_EDITING=True) wont work here + Page.register_request_processor( + processors.frontendediting_request_processor, + key='frontend_editing') + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=1', + follow=True) + self.assertRedirects(response, page.get_absolute_url()) + self.assertIn('class="fe_box"', response.content) + self.assertIn('frontend_editing', self.client.cookies) + + # turn off edit on site + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=0', + follow=True) + self.assertRedirects(response, page.get_absolute_url()) + self.assertNotIn('class="fe_box"', response.content) + + # anonymous user cannot front edit + self.client.logout() + response = self.client.get(page.get_absolute_url() + + '?frontend_editing=1', + follow=True) + self.assertRedirects(response, page.get_absolute_url()) + self.assertNotIn('class="fe_box"', response.content) + + # cleanup request processor + del Page.request_processors['frontend_editing'] def test_16_template_tags(self): # Directly testing template tags doesn't make any sense since From b7895600422ec5780d6915b1449f4c9636961c95 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Wed, 28 Nov 2012 12:12:39 +0100 Subject: [PATCH 0574/1590] Upgrade jquery to 1.8.3 --- feincms/static/feincms/jquery-1.8.1.min.js | 2 -- feincms/static/feincms/jquery-1.8.3.min.js | 2 ++ feincms/templates/admin/feincms/fe_editor.html | 2 +- feincms/templates/admin/feincms/fe_editor_done.html | 2 +- feincms/templates/admin/feincms/fe_tools.html | 2 +- feincms/templates/admin/feincms/item_editor.html | 2 +- feincms/templates/admin/feincms/tree_editor.html | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 feincms/static/feincms/jquery-1.8.1.min.js create mode 100644 feincms/static/feincms/jquery-1.8.3.min.js diff --git a/feincms/static/feincms/jquery-1.8.1.min.js b/feincms/static/feincms/jquery-1.8.1.min.js deleted file mode 100644 index e7f2a292b..000000000 --- a/feincms/static/feincms/jquery-1.8.1.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v@1.8.1 jquery.com | jquery.org/license */ -(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.1",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":a.toString().replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||f.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return typeof a=="object"?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length||!d)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||++p.uuid:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")===0&&(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)~f.indexOf(" "+b[g]+" ")||(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>-1)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,""+d),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,k,l,m,n=(p._data(this,"events")||{})[c.type]||[],o=n.delegateCount,q=[].slice.call(arguments),r=!c.exclusive&&!c.namespace,s=p.event.special[c.type]||{},t=[];q[0]=c,c.delegateTarget=this;if(s.preDispatch&&s.preDispatch.call(this,c)===!1)return;if(o&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<o;d++)k=n[d],l=k.selector,h[l]===b&&(h[l]=p(l,this).index(f)>=0),h[l]&&j.push(k);j.length&&t.push({elem:f,matches:j})}n.length>o&&t.push({elem:this,matches:n.slice(o)});for(d=0;d<t.length&&!c.isPropagationStopped();d++){i=t[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){k=i.matches[e];if(r||!c.namespace&&!k.namespace||c.namespace_re&&c.namespace_re.test(k.namespace))c.data=k.data,c.handleObj=k,g=((p.event.special[k.origType]||{}).handle||k.handler).apply(i.elem,q),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return s.postDispatch&&s.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function $(a,b,c,d){c=c||[],b=b||q;var e,f,g,j,k=b.nodeType;if(k!==1&&k!==9)return[];if(!a||typeof a!="string")return c;g=h(b);if(!g&&!d)if(e=L.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&i(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return u.apply(c,t.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&X&&b.getElementsByClassName)return u.apply(c,t.call(b.getElementsByClassName(j),0)),c}return bk(a,b,c,d,g)}function _(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function ba(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bb(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bc(a,b,c,d){var e,g,h,i,j,k,l,m,n,p,r=!c&&b!==q,s=(r?"<s>":"")+a.replace(H,"$1<s>"),u=y[o][s];if(u)return d?0:t.call(u,0);j=a,k=[],m=0,n=f.preFilter,p=f.filter;while(j){if(!e||(g=I.exec(j)))g&&(j=j.slice(g[0].length),h.selector=l),k.push(h=[]),l="",r&&(j=" "+j);e=!1;if(g=J.exec(j))l+=g[0],j=j.slice(g[0].length),e=h.push({part:g.pop().replace(H," "),string:g[0],captures:g});for(i in p)(g=S[i].exec(j))&&(!n[i]||(g=n[i](g,b,c)))&&(l+=g[0],j=j.slice(g[0].length),e=h.push({part:i,string:g.shift(),captures:g}));if(!e)break}return l&&(h.selector=l),d?j.length:j?$.error(a):t.call(y(s,k),0)}function bd(a,b,e,f){var g=b.dir,h=s++;return a||(a=function(a){return a===e}),b.first?function(b){while(b=b[g])if(b.nodeType===1)return a(b)&&b}:f?function(b){while(b=b[g])if(b.nodeType===1&&a(b))return b}:function(b){var e,f=h+"."+c,i=f+"."+d;while(b=b[g])if(b.nodeType===1){if((e=b[o])===i)return b.sizset;if(typeof e=="string"&&e.indexOf(f)===0){if(b.sizset)return b}else{b[o]=i;if(a(b))return b.sizset=!0,b;b.sizset=!1}}}}function be(a,b){return a?function(c){var d=b(c);return d&&a(d===!0?c:d)}:b}function bf(a,b,c){var d,e,g=0;for(;d=a[g];g++)f.relative[d.part]?e=bd(e,f.relative[d.part],b,c):e=be(e,f.filter[d.part].apply(null,d.captures.concat(b,c)));return e}function bg(a){return function(b){var c,d=0;for(;c=a[d];d++)if(c(b))return!0;return!1}}function bh(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)$(a,b[e],c,d)}function bi(a,b,c,d,e,g){var h,i=f.setFilters[b.toLowerCase()];return i||$.error(b),(a||!(h=e))&&bh(a||"*",d,h=[],e),h.length>0?i(h,c,g):[]}function bj(a,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s=0,t=a.length,v=S.POS,w=new RegExp("^"+v.source+"(?!"+A+")","i"),x=function(){var a=1,c=arguments.length-2;for(;a<c;a++)arguments[a]===b&&(n[a]=b)};for(;s<t;s++){f=a[s],g="",m=e;for(h=0,i=f.length;h<i;h++){j=f[h],k=j.string;if(j.part==="PSEUDO"){v.exec(""),l=0;while(n=v.exec(k)){o=!0,p=v.lastIndex=n.index+n[0].length;if(p>l){g+=k.slice(l,n.index),l=p,q=[c],J.test(g)&&(m&&(q=m),m=e);if(r=O.test(g))g=g.slice(0,-5).replace(J,"$&*"),l++;n.length>1&&n[0].replace(w,x),m=bi(g,n[1],n[2],q,m,r)}g=""}}o||(g+=k),o=!1}g?J.test(g)?bh(g,m||[c],d,e):$(g,c,d,e?e.concat(m):m):u.apply(d,m)}return t===1?d:$.uniqueSort(d)}function bk(a,b,e,g,h){a=a.replace(H,"$1");var i,k,l,m,n,o,p,q,r,s,v=bc(a,b,h),w=b.nodeType;if(S.POS.test(a))return bj(v,b,e,g);if(g)i=t.call(g,0);else if(v.length===1){if((o=t.call(v[0],0)).length>2&&(p=o[0]).part==="ID"&&w===9&&!h&&f.relative[o[1].part]){b=f.find.ID(p.captures[0].replace(R,""),b,h)[0];if(!b)return e;a=a.slice(o.shift().string.length)}r=(v=N.exec(o[0].string))&&!v.index&&b.parentNode||b,q="";for(n=o.length-1;n>=0;n--){p=o[n],s=p.part,q=p.string+q;if(f.relative[s])break;if(f.order.test(s)){i=f.find[s](p.captures[0].replace(R,""),r,h);if(i==null)continue;a=a.slice(0,a.length-q.length)+q.replace(S[s],""),a||u.apply(e,t.call(i,0));break}}}if(a){k=j(a,b,h),c=k.dirruns++,i==null&&(i=f.find.TAG("*",N.test(a)&&b.parentNode||b));for(n=0;m=i[n];n++)d=k.runs++,k(m)&&e.push(m)}return e}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=a.document,r=q.documentElement,s=0,t=[].slice,u=[].push,v=function(a,b){return a[o]=b||!0,a},w=function(){var a={},b=[];return v(function(c,d){return b.push(c)>f.cacheLength&&delete a[b.shift()],a[c]=d},a)},x=w(),y=w(),z=w(),A="[\\x20\\t\\r\\n\\f]",B="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",C=B.replace("w","w#"),D="([*^$|!~]?=)",E="\\["+A+"*("+B+")"+A+"*(?:"+D+A+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+C+")|)|)"+A+"*\\]",F=":("+B+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+E+")|[^:]|\\\\.)*|.*))\\)|)",G=":(nth|eq|gt|lt|first|last|even|odd)(?:\\(((?:-\\d)?\\d*)\\)|)(?=[^-]|$)",H=new RegExp("^"+A+"+|((?:^|[^\\\\])(?:\\\\.)*)"+A+"+$","g"),I=new RegExp("^"+A+"*,"+A+"*"),J=new RegExp("^"+A+"*([\\x20\\t\\r\\n\\f>+~])"+A+"*"),K=new RegExp(F),L=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,M=/^:not/,N=/[\x20\t\r\n\f]*[+~]/,O=/:not\($/,P=/h\d/i,Q=/input|select|textarea|button/i,R=/\\(?!\\)/g,S={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),NAME:new RegExp("^\\[name=['\"]?("+B+")['\"]?\\]"),TAG:new RegExp("^("+B.replace("w","w*")+")"),ATTR:new RegExp("^"+E),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|nth|last|first)-child(?:\\("+A+"*(even|odd|(([+-]|)(\\d*)n|)"+A+"*(?:([+-]|)"+A+"*(\\d+)|))"+A+"*\\)|)","i"),POS:new RegExp(G,"ig"),needsContext:new RegExp("^"+A+"*[>+~]|"+G,"i")},T=function(a){var b=q.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},U=T(function(a){return a.appendChild(q.createComment("")),!a.getElementsByTagName("*").length}),V=T(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),W=T(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),X=T(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),Y=T(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",r.insertBefore(a,r.firstChild);var b=q.getElementsByName&&q.getElementsByName(o).length===2+q.getElementsByName(o+0).length;return e=!q.getElementById(o),r.removeChild(a),b});try{t.call(r.childNodes,0)[0].nodeType}catch(Z){t=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}$.matches=function(a,b){return $(a,null,null,b)},$.matchesSelector=function(a,b){return $(b,null,null,[a]).length>0},g=$.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=g(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=g(b);return c},h=$.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},i=$.contains=r.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:r.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},$.attr=function(a,b){var c,d=h(a);return d||(b=b.toLowerCase()),f.attrHandle[b]?f.attrHandle[b](a):W||d?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},f=$.selectors={cacheLength:50,createPseudo:v,match:S,order:new RegExp("ID|TAG"+(Y?"|NAME":"")+(X?"|CLASS":"")),attrHandle:V?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:e?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:U?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(R,""),a[3]=(a[4]||a[5]||"").replace(R,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||$.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&$.error(a[0]),a},PSEUDO:function(a,b,c){var d,e;if(S.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(d=a[4])K.test(d)&&(e=bc(d,b,c,!0))&&(e=d.indexOf(")",d.length-e)-d.length)&&(d=d.slice(0,e),a[0]=a[0].slice(0,e)),a[2]=d;return a.slice(0,3)}},filter:{ID:e?function(a){return a=a.replace(R,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(R,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(R,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=x[o][a];return b||(b=x(a,new RegExp("(^|"+A+")"+a+"("+A+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return b?function(d){var e=$.attr(d,a),f=e+"";if(e==null)return b==="!=";switch(b){case"=":return f===c;case"!=":return f!==c;case"^=":return c&&f.indexOf(c)===0;case"*=":return c&&f.indexOf(c)>-1;case"$=":return c&&f.substr(f.length-c.length)===c;case"~=":return(" "+f+" ").indexOf(c)>-1;case"|=":return f===c||f.substr(0,c.length+1)===c+"-"}}:function(b){return $.attr(b,a)!=null}},CHILD:function(a,b,c,d){if(a==="nth"){var e=s++;return function(a){var b,f,g=0,h=a;if(c===1&&d===0)return!0;b=a.parentNode;if(b&&(b[o]!==e||!a.sizset)){for(h=b.firstChild;h;h=h.nextSibling)if(h.nodeType===1){h.sizset=++g;if(h===a)break}b[o]=e}return f=a.sizset-d,c===0?f===0:f%c===0&&f/c>=0}}return function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b,c,d){var e,g=f.pseudos[a]||f.pseudos[a.toLowerCase()];return g||$.error("unsupported pseudo: "+a),g[o]?g(b,c,d):g.length>1?(e=[a,a,"",b],function(a){return g(a,0,e)}):g}},pseudos:{not:v(function(a,b,c){var d=j(a.replace(H,"$1"),b,c);return function(a){return!d(a)}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!f.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},contains:v(function(a){return function(b){return(b.textContent||b.innerText||g(b)).indexOf(a)>-1}}),has:v(function(a){return function(b){return $(a,b).length>0}}),header:function(a){return P.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:_("radio"),checkbox:_("checkbox"),file:_("file"),password:_("password"),image:_("image"),submit:ba("submit"),reset:ba("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return Q.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b,c){return c?a.slice(1):[a[0]]},last:function(a,b,c){var d=a.pop();return c?a:[d]},even:function(a,b,c){var d=[],e=c?1:0,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},odd:function(a,b,c){var d=[],e=c?0:1,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},lt:function(a,b,c){return c?a.slice(+b):a.slice(0,+b)},gt:function(a,b,c){return c?a.slice(0,+b+1):a.slice(+b+1)},eq:function(a,b,c){var d=a.splice(+b,1);return c?a:d}}},k=r.compareDocumentPosition?function(a,b){return a===b?(l=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return l=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bb(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bb(e[j],f[j]);return j===c?bb(a,f[j],-1):bb(e[j],b,1)},[0,0].sort(k),m=!l,$.uniqueSort=function(a){var b,c=1;l=m,a.sort(k);if(l)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},$.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},j=$.compile=function(a,b,c){var d,e,f,g=z[o][a];if(g&&g.context===b)return g;d=bc(a,b,c);for(e=0,f=d.length;e<f;e++)d[e]=bf(d[e],b,c);return g=z(a,bg(d)),g.context=b,g.runs=g.dirruns=0,g},q.querySelectorAll&&function(){var a,b=bk,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[],f=[":active"],g=r.matchesSelector||r.mozMatchesSelector||r.webkitMatchesSelector||r.oMatchesSelector||r.msMatchesSelector;T(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+A+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),T(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+A+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=e.length&&new RegExp(e.join("|")),bk=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a)))if(d.nodeType===9)try{return u.apply(f,t.call(d.querySelectorAll(a),0)),f}catch(i){}else if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){var j,k,l,m=d.getAttribute("id"),n=m||o,p=N.test(a)&&d.parentNode||d;m?n=n.replace(c,"\\$&"):d.setAttribute("id",n),j=bc(a,d,h),n="[id='"+n+"']";for(k=0,l=j.length;k<l;k++)j[k]=n+j[k].selector;try{return u.apply(f,t.call(p.querySelectorAll(j.join(",")),0)),f}catch(i){}finally{m||d.removeAttribute("id")}}return b(a,d,f,g,h)},g&&(T(function(b){a=g.call(b,"div");try{g.call(b,"[test!='']:sizzle"),f.push(S.PSEUDO.source,S.POS.source,"!=")}catch(c){}}),f=new RegExp(f.join("|")),$.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!h(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=g.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return $(c,null,null,[b]).length>0})}(),f.setFilters.nth=f.setFilters.eq,f.filters=f.pseudos,$.attr=p.attr,p.find=$,p.expr=$.selectors,p.expr[":"]=p.expr.pseudos,p.unique=$.uniqueSort,p.text=$.getText,p.isXMLDoc=$.isXML,p.contains=$.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{cj=f.href}catch(cy){cj=e.createElement("a"),cj.href="",cj=cj.href}ck=ct.exec(cj.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:cj,isLocal:cn.test(ck[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=""+(c||y),k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,ck[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase()),l.crossDomain=!(!i||i[1]==ck[1]&&i[2]==ck[2]&&(i[3]||(i[1]==="http:"?80:443))==(ck[3]||(ck[1]==="http:"?80:443)))),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e,f=this.createTween(a,b),g=cQ.exec(b),h=f.cur(),i=+h||0,j=1;if(g){c=+g[2],d=g[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&i){i=p.css(f.elem,a,!0)||c||1;do e=j=j||".5",i=i/j,p.style(f.elem,a,i+d),j=f.cur()/h;while(j!==1&&j!==e)}f.unit=d,f.start=i,f.end=g[1]?i+(g[1]+1)*c:c}return f}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j,k,l,m=this[0],n=m&&m.ownerDocument;if(!n)return;return(e=n.body)===m?p.offset.bodyOffset(m):(d=n.documentElement,p.contains(d,m)?(c=m.getBoundingClientRect(),f=da(n),g=d.clientTop||e.clientTop||0,h=d.clientLeft||e.clientLeft||0,i=f.pageYOffset||d.scrollTop,j=f.pageXOffset||d.scrollLeft,k=c.top+i-g,l=c.left+j-h,{top:k,left:l}):{top:0,left:0})},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-1.8.3.min.js b/feincms/static/feincms/jquery-1.8.3.min.js new file mode 100644 index 000000000..83589daa7 --- /dev/null +++ b/feincms/static/feincms/jquery-1.8.3.min.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/feincms/templates/admin/feincms/fe_editor.html b/feincms/templates/admin/feincms/fe_editor.html index e6c9e5238..326314c77 100644 --- a/feincms/templates/admin/feincms/fe_editor.html +++ b/feincms/templates/admin/feincms/fe_editor.html @@ -3,7 +3,7 @@ {% block extrahead %}{{ block.super }} -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.3.min.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery.alerts.js"></script> <script type="text/javascript"> diff --git a/feincms/templates/admin/feincms/fe_editor_done.html b/feincms/templates/admin/feincms/fe_editor_done.html index 36f45eb99..af6cf1868 100644 --- a/feincms/templates/admin/feincms/fe_editor_done.html +++ b/feincms/templates/admin/feincms/fe_editor_done.html @@ -1,4 +1,4 @@ -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.3.min.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> <script type="text/javascript"> var feincms = { diff --git a/feincms/templates/admin/feincms/fe_tools.html b/feincms/templates/admin/feincms/fe_tools.html index cc3a941bb..48ea3a1fe 100644 --- a/feincms/templates/admin/feincms/fe_tools.html +++ b/feincms/templates/admin/feincms/fe_tools.html @@ -5,7 +5,7 @@ (function () { // load jQuery if not yet present if (typeof(feincms) == "undefined") { - var jquery_url = "{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"; + var jquery_url = "{{ STATIC_URL }}feincms/jquery-1.8.3.min.js"; document.write(unescape('%3Cscript src="' + jquery_url + '" type="text/javascript"%3E%3C/script%3E')); } })(); diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index c3743bd64..091dbabab 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -3,7 +3,7 @@ {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.3.min.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> {% endblock %} diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index c2c6c96b8..f7c30cf99 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -6,7 +6,7 @@ <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}feincms/style.css" /> <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}feincms/fein_tree.css" /> -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.1.min.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-1.8.3.min.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery-ui-1.8.22.custom.min.js"></script> <script type="text/javascript"> var feincms = { From 9dac59280ca3884cfb07c461f01f7530bc2bbc4a Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Wed, 28 Nov 2012 12:17:13 +0100 Subject: [PATCH 0575/1590] Upgrade jquery.json to 2.4 --- feincms/static/feincms/jquery.json-1.3.js | 156 ------------------ feincms/static/feincms/jquery.json-2.4.min.js | 23 +++ .../templates/admin/content/table/init.html | 2 +- 3 files changed, 24 insertions(+), 157 deletions(-) delete mode 100644 feincms/static/feincms/jquery.json-1.3.js create mode 100644 feincms/static/feincms/jquery.json-2.4.min.js diff --git a/feincms/static/feincms/jquery.json-1.3.js b/feincms/static/feincms/jquery.json-1.3.js deleted file mode 100644 index bbdfbad38..000000000 --- a/feincms/static/feincms/jquery.json-1.3.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - * jQuery JSON Plugin - * version: 1.0 (2008-04-17) - * - * This document is licensed as free software under the terms of the - * MIT License: http://www.opensource.org/licenses/mit-license.php - * - * Brantley Harris technically wrote this plugin, but it is based somewhat - * on the JSON.org website's http://www.json.org/json2.js, which proclaims: - * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that - * I uphold. I really just cleaned it up. - * - * It is also based heavily on MochiKit's serializeJSON, which is - * copywrited 2005 by Bob Ippolito. - */ - -(function($) { - function toIntegersAtLease(n) - // Format integers to have at least two digits. - { - return n < 10 ? '0' + n : n; - } - - Date.prototype.toJSON = function(date) - // Yes, it polutes the Date namespace, but we'll allow it here, as - // it's damned usefull. - { - return this.getUTCFullYear() + '-' + - toIntegersAtLease(this.getUTCMonth()) + '-' + - toIntegersAtLease(this.getUTCDate()); - }; - - var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g; - var meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }; - - $.quoteString = function(string) - // Places quotes around a string, inteligently. - // If the string contains no control characters, no quote characters, and no - // backslash characters, then we can safely slap some quotes around it. - // Otherwise we must also replace the offending characters with safe escape - // sequences. - { - if (escapeable.test(string)) - { - return '"' + string.replace(escapeable, function (a) - { - var c = meta[a]; - if (typeof c === 'string') { - return c; - } - c = a.charCodeAt(); - return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16); - }) + '"'; - } - return '"' + string + '"'; - }; - - $.toJSON = function(o, compact) - { - var type = typeof(o); - - if (type == "undefined") - return "undefined"; - else if (type == "number" || type == "boolean") - return o + ""; - else if (o === null) - return "null"; - - // Is it a string? - if (type == "string") - { - return $.quoteString(o); - } - - // Does it have a .toJSON function? - if (type == "object" && typeof o.toJSON == "function") - return o.toJSON(compact); - - // Is it an array? - if (type != "function" && typeof(o.length) == "number") - { - var ret = []; - for (var i = 0; i < o.length; i++) { - ret.push( $.toJSON(o[i], compact) ); - } - if (compact) - return "[" + ret.join(",") + "]"; - else - return "[" + ret.join(", ") + "]"; - } - - // If it's a function, we have to warn somebody! - if (type == "function") { - throw new TypeError("Unable to convert object of type 'function' to json."); - } - - // It's probably an object, then. - var ret = []; - for (var k in o) { - var name; - type = typeof(k); - - if (type == "number") - name = '"' + k + '"'; - else if (type == "string") - name = $.quoteString(k); - else - continue; //skip non-string or number keys - - var val = $.toJSON(o[k], compact); - if (typeof(val) != "string") { - // skip non-serializable values - continue; - } - - if (compact) - ret.push(name + ":" + val); - else - ret.push(name + ": " + val); - } - return "{" + ret.join(", ") + "}"; - }; - - $.compactJSON = function(o) - { - return $.toJSON(o, true); - }; - - $.evalJSON = function(src) - // Evals JSON that we know to be safe. - { - return eval("(" + src + ")"); - }; - - $.secureEvalJSON = function(src) - // Evals JSON in a way that is *more* secure. - { - var filtered = src; - filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@'); - filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); - filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); - - if (/^[\],:{}\s]*$/.test(filtered)) - return eval("(" + src + ")"); - else - throw new SyntaxError("Error parsing JSON, source is not valid."); - }; -})(feincms.jQuery); diff --git a/feincms/static/feincms/jquery.json-2.4.min.js b/feincms/static/feincms/jquery.json-2.4.min.js new file mode 100644 index 000000000..87050c9d9 --- /dev/null +++ b/feincms/static/feincms/jquery.json-2.4.min.js @@ -0,0 +1,23 @@ +/*! jQuery JSON plugin 2.4.0 | code.google.com/p/jquery-json */ +(function($){'use strict';var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},hasOwn=Object.prototype.hasOwnProperty;$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';} +var pairs,k,name,val,type=$.type(o);if(type==='undefined'){return undefined;} +if(type==='number'||type==='boolean'){return String(o);} +if(type==='string'){return $.quoteString(o);} +if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());} +if(type==='date'){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;} +if(day<10){day='0'+day;} +if(hours<10){hours='0'+hours;} +if(minutes<10){minutes='0'+minutes;} +if(seconds<10){seconds='0'+seconds;} +if(milli<100){milli='0'+milli;} +if(milli<10){milli='0'+milli;} +return'"'+year+'-'+month+'-'+day+'T'+ +hours+':'+minutes+':'+seconds+'.'+milli+'Z"';} +pairs=[];if($.isArray(o)){for(k=0;k<o.length;k++){pairs.push($.toJSON(o[k])||'null');} +return'['+pairs.join(',')+']';} +if(typeof o==='object'){for(k in o){if(hasOwn.call(o,k)){type=typeof k;if(type==='number'){name='"'+k+'"';}else if(type==='string'){name=$.quoteString(k);}else{continue;} +type=typeof o[k];if(type!=='function'&&type!=='undefined'){val=$.toJSON(o[k]);pairs.push(name+':'+val);}}} +return'{'+pairs.join(',')+'}';}};$.evalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){return eval('('+str+')');};$.secureEvalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){var filtered=str.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)){return eval('('+str+')');} +throw new SyntaxError('Error parsing JSON, source is not valid.');};$.quoteString=function(str){if(str.match(escape)){return'"'+str.replace(escape,function(a){var c=meta[a];if(typeof c==='string'){return c;} +c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';} +return'"'+str+'"';};}(jQuery)); \ No newline at end of file diff --git a/feincms/templates/admin/content/table/init.html b/feincms/templates/admin/content/table/init.html index 149769a75..3c6434511 100644 --- a/feincms/templates/admin/content/table/init.html +++ b/feincms/templates/admin/content/table/init.html @@ -1,5 +1,5 @@ {% load adminmedia i18n %} -<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery.json-1.3.js"></script> +<script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery.json-2.4.min.js"></script> <script type="text/javascript"> //<![CDATA[ From 914eb0c2943bd0765af0de5a839f9a5e3c4d544f Mon Sep 17 00:00:00 2001 From: Stefan Reinhard <sr@feinheit.ch> Date: Sun, 2 Dec 2012 21:52:43 +0100 Subject: [PATCH 0576/1590] fix AttributeError when using cleanse with section content --- feincms/content/section/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index b7646116a..0e27b7190 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -95,11 +95,11 @@ def save(self, *args, **kwargs): try: # Passes the rich text content as first argument because # the passed callable has been converted into a bound method - self.richtext = self.cleanse(self.text) + self.richtext = self.cleanse(self.richtext) except TypeError: # Call the original callable, does not pass the rich richtext # content instance along - self.richtext = self.cleanse.im_func(self.text) + self.richtext = self.cleanse.im_func(self.richtext) super(SectionContent, self).save(*args, **kwargs) save.alters_data = True From 061dc775db71d2d22cef9cce22e33a4bc85fe4dd Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Tue, 4 Dec 2012 18:29:10 +0100 Subject: [PATCH 0577/1590] Always connect the pre_save handler to null out _ct_inventory, so the in-memory instance correctly reflects the db's state. --- feincms/module/extensions/ct_tracker.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 6628f0b13..065b7310f 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -139,9 +139,8 @@ def register(cls, admin_cls): cls.add_to_class('_ct_inventory', JSONField(_('content types'), editable=False, blank=True, null=True)) cls.content_proxy_class = TrackerContentProxy + pre_save.connect(single_pre_save_handler, sender=cls) if hasattr(cls, 'get_descendants'): post_save.connect(tree_post_save_handler, sender=cls) - else: - pre_save.connect(single_pre_save_handler, sender=cls) # ------------------------------------------------------------------------ From bc7c3e0204a147c4d372974739e1c38126a55fd8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 6 Dec 2012 09:43:11 +0100 Subject: [PATCH 0578/1590] Fix #371: Stop loading the adminmedia template library Thanks to Christian Jensen for the report! --- feincms/templates/admin/content/table/init.html | 2 +- feincms/templates/admin/feincms/fe_editor.html | 2 +- feincms/templates/admin/feincms/item_editor.html | 2 +- feincms/templates/admin/feincms/tree_editor.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/templates/admin/content/table/init.html b/feincms/templates/admin/content/table/init.html index 3c6434511..ab427dd1c 100644 --- a/feincms/templates/admin/content/table/init.html +++ b/feincms/templates/admin/content/table/init.html @@ -1,4 +1,4 @@ -{% load adminmedia i18n %} +{% load i18n %} <script type="text/javascript" src="{{ STATIC_URL }}feincms/jquery.json-2.4.min.js"></script> <script type="text/javascript"> //<![CDATA[ diff --git a/feincms/templates/admin/feincms/fe_editor.html b/feincms/templates/admin/feincms/fe_editor.html index 326314c77..e8187c424 100644 --- a/feincms/templates/admin/feincms/fe_editor.html +++ b/feincms/templates/admin/feincms/fe_editor.html @@ -1,5 +1,5 @@ {% extends "admin/change_form.html" %} -{% load i18n admin_modify adminmedia %} +{% load i18n admin_modify %} {% block extrahead %}{{ block.super }} diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index 091dbabab..bcccf0387 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -1,5 +1,5 @@ {% extends "admin/change_form.html" %} -{% load i18n admin_modify adminmedia %} +{% load i18n admin_modify %} {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index f7c30cf99..997be2b3d 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -1,5 +1,5 @@ {% extends "admin/change_list.html" %} -{% load adminmedia admin_list i18n %} +{% load admin_list i18n %} {% block extrahead %} {{ block.super }} From fb613a73e725f32d05c6a049c22af87259f72a9f Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Sun, 9 Dec 2012 00:57:03 +0100 Subject: [PATCH 0579/1590] The datepublisher extension registers a response processor to modify the response's headers to reflect the publication end date (Cache-Control max-age and Expires headers). --- feincms/module/extensions/datepublisher.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 5430fafa4..9c179d127 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -13,6 +13,7 @@ from django.db import models from django.db.models import Q from django.utils import timezone +from django.utils.cache import patch_response_headers from django.utils.translation import ugettext_lazy as _ # ------------------------------------------------------------------------ @@ -45,6 +46,20 @@ def granular_now(n=None): return timezone.make_aware(datetime(n.year, n.month, n.day, n.hour, (n.minute // 5) * 5), n.tzinfo) +# ------------------------------------------------------------------------ +def datepublisher_response_processor(page, request, response): + """ + This response processor is automatically added when the datepublisher + extension is registered. It sets the response headers to match with + the publication end date of the page so that upstream caches and + the django caching middleware know when to expunge the copy. + """ + expires = page.publication_end_date + if expires is not None: + now = datetime.now() + delta = int((expires - now).total_seconds()) + patch_response_headers(response, delta) + # ------------------------------------------------------------------------ def register(cls, admin_cls): cls.add_to_class('publication_date', @@ -75,6 +90,9 @@ def granular_save(obj, *args, **kwargs): Q(publication_end_date__gt=granular_now)), key='datepublisher') + # Processor to patch up response headers for expiry date + cls.register_response_processor(datepublisher_response_processor) + def datepublisher_admin(self, page): return u'%s – %s' % ( format_date(page.publication_date), From 0d617aaba71e1df74779d95f6bff49ad563a556e Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Mon, 10 Dec 2012 14:49:46 +0100 Subject: [PATCH 0580/1590] Instead of submitting the form with .submit(), trigger a click on the "Save" button to allow registered submit hooks to run. This should fix the "Switching templates loses tagging" phenomenon in issue #372. Also use a stricter selector for the main form, since we might have several forms on that page. --- feincms/static/feincms/item_editor.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 5e9a7b09d..5e1d4b675 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -454,7 +454,9 @@ if(!Array.indexOf) { input_element.checked = true; - $('form').append('<input type="hidden" name="_continue" value="1" />').submit(); + $('#page_form').append('<input type="hidden" name="_continue" value="1" />'); + $('#page_form input[type=submit][name=_save]').click(); + } else { $("div#popup_bg").remove(); $(input_element).val($(input_element).data('original_value')); // Restore original value From 9987bbf7ba6cb3e5a117895c1bfce89785364241 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Tue, 11 Dec 2012 10:59:17 +0100 Subject: [PATCH 0581/1590] Add a comment explaining the rationale behind the form submit method --- feincms/static/feincms/item_editor.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 5e1d4b675..034c3dae6 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -455,6 +455,9 @@ if(!Array.indexOf) { input_element.checked = true; $('#page_form').append('<input type="hidden" name="_continue" value="1" />'); + /* Simulate a click on the save button instead of form.submit(), so + that the submit handlers from FilteredSelectMultiple get + invoked. See Issue #372 */ $('#page_form input[type=submit][name=_save]').click(); } else { From 20623d2c1be763c863244e2cfc366b381cfc04b9 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Wed, 12 Dec 2012 15:13:57 +0100 Subject: [PATCH 0582/1590] Admin beautification: Mark inactive pages in a different colour so we have a bit more structure in the sea of blue. --- feincms/admin/tree_editor.py | 10 ++++++---- feincms/static/feincms/fein_tree.css | 13 ++++++++++++- feincms/static/feincms/fein_tree.js | 6 ++++++ feincms/static/feincms/toolbox.js | 10 ++++++++-- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 883017fa8..d60098055 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -91,7 +91,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): a = [ '<input type="checkbox"', value and ' checked="checked"' or '', - ' onclick="return inplace_toggle_boolean(%d, \'%s\')"' % (item.pk, attr), + ' onclick="inplace_toggle_boolean(%d, \'%s\').then($.fn.recolorRows);"' % (item.pk, attr), ' />', text, ] @@ -282,7 +282,7 @@ def _toggle_boolean(self, request): self._collect_editable_booleans() - if not self._ajax_editable_booleans.has_key(attr): + if not attr in self._ajax_editable_booleans: return HttpResponseBadRequest("not a valid attribute %s" % attr) try: @@ -294,12 +294,14 @@ def _toggle_boolean(self, request): logging.warning("Denied AJAX request by %s to toggle boolean %s for object %s", request.user, attr, item_id) return HttpResponseForbidden("You do not have permission to access this object") - logging.info("Processing request by %s to toggle %s on %s", request.user, attr, obj) + new_state = not getattr(obj, attr) + logging.info("Processing request by %s to toggle %s on #%d %s to %s", + request.user, attr, obj.pk, obj, "on" if new_state else "off") try: before_data = self._ajax_editable_booleans[attr](self, obj) - setattr(obj, attr, not getattr(obj, attr)) + setattr(obj, attr, new_state) obj.save() self._refresh_changelist_caches() # ???: Perhaps better a post_save signal? diff --git a/feincms/static/feincms/fein_tree.css b/feincms/static/feincms/fein_tree.css index 8047a248b..b250fe6f3 100644 --- a/feincms/static/feincms/fein_tree.css +++ b/feincms/static/feincms/fein_tree.css @@ -51,4 +51,15 @@ div#drag_line div { tr.non-editable a:link, tr.non-editable a:visited, tr.non-editable td { color: #AAA; -} \ No newline at end of file +} + + +tr.item_inactive { + color: red; + opacity: 0.7; +} + +tr.item_inactive th a { + color: red; + opacity: 0.7; +} diff --git a/feincms/static/feincms/fein_tree.js b/feincms/static/feincms/fein_tree.js index 0d5fc0944..8f20392b7 100755 --- a/feincms/static/feincms/fein_tree.js +++ b/feincms/static/feincms/fein_tree.js @@ -8,6 +8,12 @@ feincms.jQuery(function($){ $.extend($.fn.recolorRows = function() { $('tr:visible:even', this).removeClass('row2').addClass('row1'); $('tr:visible:odd', this).removeClass('row1').addClass('row2'); + + /* Mark inactive rows */ + $('tr.item_inactive').removeClass('item_inactive'); + $('div[id^=wrap_active_] input:checkbox:not(:checked)').parents('tr').addClass('item_inactive'); + $('div[id^=wrap_active_] img').parents('tr').addClass('item_inactive'); + }); function isExpandedNode(id) { diff --git a/feincms/static/feincms/toolbox.js b/feincms/static/feincms/toolbox.js index 626423de6..353e197c3 100644 --- a/feincms/static/feincms/toolbox.js +++ b/feincms/static/feincms/toolbox.js @@ -58,20 +58,26 @@ $.ajaxSetup({ /* OnClick handler to toggle a boolean field via AJAX */ function inplace_toggle_boolean(item_id, attr) { + var deferred = $.Deferred(); + $.ajax({ url: ".", type: "POST", dataType: "json", data: { '__cmd': 'toggle_boolean', 'item_id': item_id, 'attr': attr }, - success: replace_elements, + success: function(data) { + console.log("--success--"); + replace_elements(data); + deferred.resolve(); + }, error: function(xhr, status, err) { alert("Unable to toggle " + attr + ": " + xhr.responseText); } }); - return false; + return deferred.promise(); } From 3e8a3c6641d4026970102276340b6a63689ef4fd Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Wed, 12 Dec 2012 15:17:19 +0100 Subject: [PATCH 0583/1590] Duh. Remove debug print. --- feincms/static/feincms/toolbox.js | 1 - 1 file changed, 1 deletion(-) diff --git a/feincms/static/feincms/toolbox.js b/feincms/static/feincms/toolbox.js index 353e197c3..7f85bb64e 100644 --- a/feincms/static/feincms/toolbox.js +++ b/feincms/static/feincms/toolbox.js @@ -67,7 +67,6 @@ function inplace_toggle_boolean(item_id, attr) { data: { '__cmd': 'toggle_boolean', 'item_id': item_id, 'attr': attr }, success: function(data) { - console.log("--success--"); replace_elements(data); deferred.resolve(); }, From 8858c41a8cf4937e1e7f21d9e2cb8b21ca2b4375 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Thu, 13 Dec 2012 12:15:47 +0100 Subject: [PATCH 0584/1590] Tweak inactive page colour --- feincms/static/feincms/fein_tree.css | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/feincms/static/feincms/fein_tree.css b/feincms/static/feincms/fein_tree.css index b250fe6f3..182c9396b 100644 --- a/feincms/static/feincms/fein_tree.css +++ b/feincms/static/feincms/fein_tree.css @@ -55,11 +55,9 @@ tr.non-editable a:link, tr.non-editable a:visited, tr.non-editable td { tr.item_inactive { - color: red; - opacity: 0.7; + color: rgb(221, 17, 68); } tr.item_inactive th a { - color: red; - opacity: 0.7; + color: rgb(221, 17, 68); } From c88b6cac141c5ae0bc884af7b9e5f778df79fd13 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 19 Dec 2012 10:08:31 +0100 Subject: [PATCH 0585/1590] Stop depending on SITE_ID being set --- feincms/module/page/models.py | 2 +- feincms/utils/__init__.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index b8d21d90b..d0c93d74a 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -177,7 +177,7 @@ class Page(create_base_model(MPTTModel), ContentModelMixin): _cached_url = models.CharField(_('Cached URL'), max_length=255, blank=True, editable=False, default='', db_index=True) - cache_key_components = [ lambda p: django_settings.SITE_ID, + cache_key_components = [ lambda p: getattr(django_settings, 'SITE_ID', 0), lambda p: p._django_content_type.id, lambda p: p.id ] diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 562d7bc4f..e85e8f97d 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -86,7 +86,11 @@ def path_to_cache_key(path, max_length=200, prefix=""): m.update(path) path = m.hexdigest() + '-' + path[:max_length - 20] - cache_key = 'FEINCMS:%d:%s:%s' % (django_settings.SITE_ID, prefix, path) + cache_key = 'FEINCMS:%d:%s:%s' % ( + getattr(django_settings, 'SITE_ID', 0), + prefix, + path, + ) return cache_key # ------------------------------------------------------------------------ From 512c394aa19b3b6b16c989f7ae7f718c0050926d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 19 Dec 2012 14:37:19 +0100 Subject: [PATCH 0586/1590] Fix an inconsistency in get_original_translation: Raise if not exists --- feincms/module/extensions/translations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 5ad728788..cf4c7fd55 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -172,7 +172,9 @@ def available_translations(self): def get_original_translation(self, *args, **kwargs): if is_primary_language(self.language): return self - return self.translation_of + if self.translation_of: + return self.translation_of + raise self.DoesNotExist @monkeypatch_property(cls) def original_translation(self): From 992703b8e8ef8d6fe581bf33b06b972df9cbf2bc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 8 Jan 2013 18:07:07 +0100 Subject: [PATCH 0587/1590] Fix #376: Intermittent crashes in RSSContent.cache_content Sometimes, the feeds seem to have no `link` element. Stop the update_rsscontent management command from crashing hard when this happens. Thanks to Piet Delport for the report! --- feincms/content/rss/models.py | 2 +- feincms/templates/content/rss/content.html | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/feincms/content/rss/models.py b/feincms/content/rss/models.py index 196e5e1d3..579a5bb78 100644 --- a/feincms/content/rss/models.py +++ b/feincms/content/rss/models.py @@ -42,7 +42,7 @@ def cache_content(self, date_format=None, save=True): self.rendered_content = render_to_string('content/rss/content.html', { 'feed_title': self.title, - 'feed_link': feed['feed']['link'], + 'feed_link': feed['feed'].get('link'), 'entries': entries, }) self.last_updated = timezone.now() diff --git a/feincms/templates/content/rss/content.html b/feincms/templates/content/rss/content.html index c1eaaf923..7c54a7282 100644 --- a/feincms/templates/content/rss/content.html +++ b/feincms/templates/content/rss/content.html @@ -1,8 +1,9 @@ -<h2><a href="{{ feed_link }}">{{ feed_title }}</a></h2> +{% if feed_link %}<h2><a href="{{ feed_link }}">{{ feed_title }}</a></h2> +{% else %}<h2>{{ feed_title }}</h2> +{% endif %} <ul> {% for entry in entries %} <li><a href="{{ entry.link }}">{{ entry.title }}</a></li> {% endfor %} </ul> - From 163b0c4a5030c0d8107a2b7040cfa9f89530e324 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 5 Nov 2012 15:55:31 +0100 Subject: [PATCH 0588/1590] Blog entries do not have a redirect_to attribute --- feincms/module/extensions/translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 044756418..d3395f09b 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -99,7 +99,7 @@ def translations_request_processor_explicit(page, request): # ------------------------------------------------------------------------ def translations_request_processor_standard(page, request): # If this page is just a redirect, don't do any language specific setup - if page.redirect_to: + if getattr(page, 'redirect_to', None): return if page.language == translation.get_language(): From a51670d8d4420265eebbc3b50ea4f14ac1ae0b5e Mon Sep 17 00:00:00 2001 From: Greg Turner <greg@interaction.net.au> Date: Thu, 10 Jan 2013 15:03:43 +1100 Subject: [PATCH 0589/1590] Adding a 'force' parameter to ensure_completely_loaded, and a forced call when a content_type is added. See #323 --- feincms/__init__.py | 4 ++-- feincms/models.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 1a9d5d1a8..7fb46bea6 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -23,7 +23,7 @@ def __getattr__(self, attr): COMPLETELY_LOADED = False -def ensure_completely_loaded(): +def ensure_completely_loaded(force=False): """ This method ensures all models are completely loaded @@ -36,7 +36,7 @@ def ensure_completely_loaded(): """ global COMPLETELY_LOADED - if COMPLETELY_LOADED: + if COMPLETELY_LOADED and not force: return True # Ensure meta information concerning related fields is up-to-date. diff --git a/feincms/models.py b/feincms/models.py index 112aabfab..47cacced6 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -729,6 +729,7 @@ class Meta(feincms_content_base.Meta): for key, includes in model.feincms_item_editor_includes.items(): cls.feincms_item_editor_includes.setdefault(key, set()).update(includes) + ensure_completely_loaded(force=True) return new_type @property From 9b777123d131354a9d4648b542c7f43fa092234f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 10 Jan 2013 10:25:51 +0100 Subject: [PATCH 0590/1590] Fix #373: Video embedding on SSL-secured websites --- feincms/templates/content/video/vimeo.html | 4 ++-- feincms/templates/content/video/youtube.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/templates/content/video/vimeo.html b/feincms/templates/content/video/vimeo.html index bf2a848fe..0da5dc8b8 100644 --- a/feincms/templates/content/video/vimeo.html +++ b/feincms/templates/content/video/vimeo.html @@ -1,6 +1,6 @@ <object width="650" height="365"> <param name="allowfullscreen" value="true" /> <param name="allowscriptaccess" value="always" /> - <param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" /> - <embed src="http://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="650" height="365"></embed> + <param name="movie" value="https://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" /> + <embed src="https://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="650" height="365"></embed> </object> diff --git a/feincms/templates/content/video/youtube.html b/feincms/templates/content/video/youtube.html index f87eb4806..0a0da7492 100644 --- a/feincms/templates/content/video/youtube.html +++ b/feincms/templates/content/video/youtube.html @@ -1,6 +1,6 @@ <object width="425" height="344"> -<param name="movie" value="http://www.youtube.com/v/{{ v }}&hl=en&fs=1&"></param> +<param name="movie" value="https://www.youtube.com/v/{{ v }}&hl=en&fs=1&"></param> <param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param> -<embed src="http://www.youtube.com/v/{{ v }}&hl=en&fs=1&" type="application/x-shockwave-flash" +<embed src="https://www.youtube.com/v/{{ v }}&hl=en&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed> </object> From 3ceb1a37d8927cb6e1e1768eb8452c9b55d950d4 Mon Sep 17 00:00:00 2001 From: Greg Turner <greg@interaction.net.au> Date: Thu, 10 Jan 2013 22:14:24 +1100 Subject: [PATCH 0591/1590] Last patch re #323 was a sledgehammer to crack a walnut. This is a better solution. --- feincms/__init__.py | 4 ++-- feincms/models.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 7fb46bea6..1a9d5d1a8 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -23,7 +23,7 @@ def __getattr__(self, attr): COMPLETELY_LOADED = False -def ensure_completely_loaded(force=False): +def ensure_completely_loaded(): """ This method ensures all models are completely loaded @@ -36,7 +36,7 @@ def ensure_completely_loaded(force=False): """ global COMPLETELY_LOADED - if COMPLETELY_LOADED and not force: + if COMPLETELY_LOADED: return True # Ensure meta information concerning related fields is up-to-date. diff --git a/feincms/models.py b/feincms/models.py index 47cacced6..7ed18a53e 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -729,7 +729,10 @@ class Meta(feincms_content_base.Meta): for key, includes in model.feincms_item_editor_includes.items(): cls.feincms_item_editor_includes.setdefault(key, set()).update(includes) - ensure_completely_loaded(force=True) + # since this content type is potentially being added after cls is + # loaded by Django, we will reload the cls's related objects cache. + # See issue #323. + cls._meta._fill_related_objects_cache() return new_type @property From caf2187b8fbe8d4c5398e03f9e281395649e7cc7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 11 Jan 2013 09:08:13 +0100 Subject: [PATCH 0592/1590] VideoContent: Use protocol-relative URLs when embedding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #373. Thanks to Simon Bächler for the suggestion. --- feincms/templates/content/video/vimeo.html | 2 +- feincms/templates/content/video/youtube.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/templates/content/video/vimeo.html b/feincms/templates/content/video/vimeo.html index 2e617abfa..9ec14ad3c 100644 --- a/feincms/templates/content/video/vimeo.html +++ b/feincms/templates/content/video/vimeo.html @@ -1,2 +1,2 @@ -<iframe src="https://player.vimeo.com/video/{{ id }}" width="650" height="365" +<iframe src="//player.vimeo.com/video/{{ id }}" width="650" height="365" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> diff --git a/feincms/templates/content/video/youtube.html b/feincms/templates/content/video/youtube.html index 0a0da7492..d16b9db91 100644 --- a/feincms/templates/content/video/youtube.html +++ b/feincms/templates/content/video/youtube.html @@ -1,6 +1,6 @@ <object width="425" height="344"> -<param name="movie" value="https://www.youtube.com/v/{{ v }}&hl=en&fs=1&"></param> +<param name="movie" value="//www.youtube.com/v/{{ v }}&hl=en&fs=1&"></param> <param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param> -<embed src="https://www.youtube.com/v/{{ v }}&hl=en&fs=1&" type="application/x-shockwave-flash" +<embed src="//www.youtube.com/v/{{ v }}&hl=en&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed> </object> From 5bf4ab87f9aa1bd4ac1c97c81fbe2157e1e26320 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 11 Jan 2013 09:08:51 +0100 Subject: [PATCH 0593/1590] VideoContent: Use protocol-relative URLs when embedding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #373. Thanks to Simon Bächler for the suggestion. --- feincms/templates/content/video/vimeo.html | 2 +- feincms/templates/content/video/youtube.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/templates/content/video/vimeo.html b/feincms/templates/content/video/vimeo.html index 0da5dc8b8..69426248c 100644 --- a/feincms/templates/content/video/vimeo.html +++ b/feincms/templates/content/video/vimeo.html @@ -2,5 +2,5 @@ <param name="allowfullscreen" value="true" /> <param name="allowscriptaccess" value="always" /> <param name="movie" value="https://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" /> - <embed src="https://vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="650" height="365"></embed> + <embed src="//vimeo.com/moogaloop.swf?clip_id={{ id }}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="650" height="365"></embed> </object> diff --git a/feincms/templates/content/video/youtube.html b/feincms/templates/content/video/youtube.html index 0a0da7492..d16b9db91 100644 --- a/feincms/templates/content/video/youtube.html +++ b/feincms/templates/content/video/youtube.html @@ -1,6 +1,6 @@ <object width="425" height="344"> -<param name="movie" value="https://www.youtube.com/v/{{ v }}&hl=en&fs=1&"></param> +<param name="movie" value="//www.youtube.com/v/{{ v }}&hl=en&fs=1&"></param> <param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param> -<embed src="https://www.youtube.com/v/{{ v }}&hl=en&fs=1&" type="application/x-shockwave-flash" +<embed src="//www.youtube.com/v/{{ v }}&hl=en&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed> </object> From e658909a255c5d8b3539a9c5d2ffc7559b4046d7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 19 Jan 2013 15:29:12 +0100 Subject: [PATCH 0594/1590] Add a test related to 3ceb1a37d8927cb6e1e1768eb8452c9b55d950d4 --- feincms/tests/cms_tests.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feincms/tests/cms_tests.py b/feincms/tests/cms_tests.py index 39b5514ca..5392010f2 100644 --- a/feincms/tests/cms_tests.py +++ b/feincms/tests/cms_tests.py @@ -127,6 +127,9 @@ def test_09_related_objects_cache(self): class Attachment(models.Model): base = models.ForeignKey(ExampleCMSBase, related_name='test_related_name') + # See issue #323 on Github. + ExampleCMSBase._meta._fill_related_objects_cache() + related_models = map( lambda x: x.model, ExampleCMSBase._meta.get_all_related_objects()) From 7e070e206d1ea3c331406775d228e38cc5b19650 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 19 Jan 2013 15:40:06 +0100 Subject: [PATCH 0595/1590] ct_tracker: One less database query when invalidating the cache --- feincms/module/extensions/ct_tracker.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 065b7310f..238b8e9a0 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -60,9 +60,9 @@ def _fetch_content_type_counts(self): self.item._ct_inventory = self._to_inventory(self._cache['counts']) - this_page = self.item.__class__.objects.filter(id=self.item.id) - this_page.update(_ct_inventory=self.item._ct_inventory) - this_page[0].invalidate_cache() + self.item.invalidate_cache() + self.item.__class__.objects.filter(id=self.item.id).update( + _ct_inventory=self.item._ct_inventory) # Run post save handler by hand if hasattr(self.item, 'get_descendants'): From 21339c0c2aa5c91854974d1ff19f2dfe193eb291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= <simon@stellanera.com> Date: Tue, 21 Aug 2012 13:02:06 +0200 Subject: [PATCH 0596/1590] Make datepublisher save aware datetimes Fixes #380. --- feincms/module/extensions/datepublisher.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index b90048712..5430fafa4 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -42,13 +42,16 @@ def granular_now(n=None): """ if n is None: n = timezone.now() - return datetime(n.year, n.month, n.day, n.hour, (n.minute // 5) * 5) + return timezone.make_aware(datetime(n.year, n.month, n.day, n.hour, + (n.minute // 5) * 5), n.tzinfo) # ------------------------------------------------------------------------ def register(cls, admin_cls): - cls.add_to_class('publication_date', models.DateTimeField(_('publication date'), + cls.add_to_class('publication_date', + models.DateTimeField(_('publication date'), default=granular_now)) - cls.add_to_class('publication_end_date', models.DateTimeField(_('publication end date'), + cls.add_to_class('publication_end_date', + models.DateTimeField(_('publication end date'), blank=True, null=True, help_text=_('Leave empty if the entry should stay active forever.'))) cls.add_to_class('latest_children', latest_children) @@ -68,7 +71,8 @@ def granular_save(obj, *args, **kwargs): if hasattr(cls._default_manager, 'add_to_active_filters'): cls._default_manager.add_to_active_filters( Q(publication_date__lte=granular_now) & - (Q(publication_end_date__isnull=True) | Q(publication_end_date__gt=granular_now)), + (Q(publication_end_date__isnull=True) | + Q(publication_end_date__gt=granular_now)), key='datepublisher') def datepublisher_admin(self, page): From 9b00b0d7e7194ca87d3bb28e5dbd5050f36789d9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 19 Jan 2013 15:45:55 +0100 Subject: [PATCH 0597/1590] Better be safe: Escape item titles in the tree editor Fixes #375. --- feincms/admin/tree_editor.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 7d4256dfa..8322adf26 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -12,7 +12,9 @@ from django.contrib import admin from django.contrib.admin.views import main from django.db.models import Q -from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, HttpResponseServerError +from django.http import (HttpResponse, HttpResponseBadRequest, + HttpResponseForbidden, HttpResponseNotFound, HttpResponseServerError) +from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _, ugettext @@ -221,9 +223,9 @@ def indented_short_title(self, item): item.pk, editable_class, 14+getattr(item, mptt_opts.level_attr)*18) # r += '<span tabindex="0">' if hasattr(item, 'short_title'): - r += item.short_title() + r += escape(item.short_title()) else: - r += unicode(item) + r += escape(unicode(item)) # r += '</span>' return mark_safe(r) indented_short_title.short_description = _('title') From 91e10f573c60095b420468e89c49e511200e4967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Fern=C3=A1ndez=20Nogueira?= <fonzzo@gmail.com> Date: Mon, 21 Jan 2013 14:44:43 +0100 Subject: [PATCH 0598/1590] Updated Spanish (es) translation .po file --- feincms/locale/es/LC_MESSAGES/django.po | 108 +++++++++++++----------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/feincms/locale/es/LC_MESSAGES/django.po b/feincms/locale/es/LC_MESSAGES/django.po index 89694b765..5b8425fcb 100644 --- a/feincms/locale/es/LC_MESSAGES/django.po +++ b/feincms/locale/es/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"PO-Revision-Date: 2013-01-21 14:33+0200\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: es\n" @@ -70,14 +70,14 @@ msgid "actions" msgstr "acciones" #: admin/tree_editor.py:429 -#, fuzzy, python-format +#, python-format msgid "Successfully deleted %s items." -msgstr "¿Confirma la eliminación del elemento?" +msgstr "%s elementos eliminados con éxito." #: admin/tree_editor.py:437 #, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "" +msgstr "Eliminar los/as %(verbose_name_plural)s seleccionados" #: content/application/models.py:272 msgid "application content" @@ -150,11 +150,11 @@ msgstr "imagen" #: content/image/models.py:46 msgid "alternate text" -msgstr "" +msgstr "text alternativo" #: content/image/models.py:47 msgid "Description of image" -msgstr "" +msgstr "Descripción de la imagen" #: content/image/models.py:48 module/medialibrary/models.py:235 msgid "caption" @@ -171,7 +171,7 @@ msgstr "posición" #: content/image/models.py:87 msgid "format" -msgstr "" +msgstr "formato" #: content/medialibrary/models.py:48 msgid "(no caption)" @@ -337,7 +337,7 @@ msgstr "vídeos" #: contrib/tagging.py:117 msgid "Tagging" -msgstr "" +msgstr "Etiquetado" #: module/blog/models.py:28 msgid "published" @@ -456,7 +456,7 @@ msgstr "traducciones" #: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" -msgstr "" +msgstr "Esto crearía un bucle en la jerarquía" #: module/medialibrary/forms.py:64 #, python-format @@ -464,36 +464,42 @@ msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" +"No se puede sobreescribir con un tipo de archivo diferente (intento " +"de sobreescribir un %(old_ext)s con un %(new_ext)s)" #: module/medialibrary/modeladmins.py:57 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" +"Se añadió con éxito %(count)d archivo de medios a la categoría " +"%(category)s." msgstr[1] "" +"Se añadieron con éxito %(count)d archivos de medios a la categoría " +"%(category)s." #: module/medialibrary/modeladmins.py:75 msgid "Add selected media files to category" -msgstr "" +msgstr "Añadir los archivos de medios seleccionados a la categoría" #: module/medialibrary/modeladmins.py:84 #, python-format msgid "ZIP file exported as %s" -msgstr "" +msgstr "Archivo ZIP exportado como %s" #: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file export failed: %s" -msgstr "" +msgstr "La exportación del archivo ZIP falló: %s" #: module/medialibrary/modeladmins.py:91 msgid "Export selected media files as zip file" -msgstr "" +msgstr "Exportar los archivos de medios selccionados como un archivo ZIP" #: module/medialibrary/modeladmins.py:134 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" -msgstr "Pre-visualización" +msgstr "Previsualización" #: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 msgid "file size" @@ -514,16 +520,16 @@ msgstr "información del archivo" #: module/medialibrary/modeladmins.py:196 #, python-format msgid "%d files imported" -msgstr "" +msgstr "importados %d archivos" #: module/medialibrary/modeladmins.py:198 #, python-format msgid "ZIP import failed: %s" -msgstr "" +msgstr "La importación del archivo ZIP falló: %s" #: module/medialibrary/modeladmins.py:200 msgid "No input file given" -msgstr "" +msgstr "No se indicó un archivo de entrada" #: module/medialibrary/models.py:43 msgid "parent" @@ -575,7 +581,7 @@ msgstr "Texto rico" #: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "" +msgstr "Archivo ZIP" #: module/medialibrary/models.py:210 msgid "Microsoft Word" @@ -599,11 +605,11 @@ msgstr "descripción" #: module/medialibrary/models.py:239 msgid "media file translation" -msgstr "traducción del archivo de media" +msgstr "traducción del archivo de medios" #: module/medialibrary/models.py:240 msgid "media file translations" -msgstr "traducciones del archivo de media" +msgstr "traducciones del archivo de medios" #: module/page/forms.py:118 msgid "This URL is already taken by an active page." @@ -611,11 +617,11 @@ msgstr "Esta URL ya está en uso en una página activa" #: module/page/forms.py:136 msgid "This URL is already taken by another active page." -msgstr "Esta URL ya está en uno por otra página activa" +msgstr "Esta URL ya está en uso por otra página activa" #: module/page/modeladmins.py:41 msgid "Other options" -msgstr "otras opciones" +msgstr "Otras opciones" #: module/page/modeladmins.py:89 module/page/models.py:145 msgid "in navigation" @@ -635,10 +641,12 @@ msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" +"El contenido de la traducción original se ha copiado en la página " +"recién creada." #: module/page/modeladmins.py:144 msgid "You don't have the necessary permissions to edit this object" -msgstr "" +msgstr "No dispone de los permisos necesarios para editar este objeto" #: module/page/modeladmins.py:159 msgid "inherited" @@ -666,8 +674,8 @@ msgid "" "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -"URL efectivo. Debe contener una '/' cuando se trata de un URL local. Este " -"campo afecta la navegación y los URLs de las sub-páginas." +"URL efectivo. Debe contener una '/' al principio y al final al cuando se trata " +"de un URL local. Este campo afecta a la navegación y a los URLs de las sub-páginas." #: module/page/models.py:148 msgid "redirect to" @@ -679,7 +687,7 @@ msgstr "URL de destino para redirecciones automáticas." #: module/page/models.py:150 msgid "Cached URL" -msgstr "URL en cache" +msgstr "URL en caché" #: module/page/models.py:161 msgid "page" @@ -711,7 +719,7 @@ msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "" -"Selecciona el módulo que provee sub-páginas para esta pagina si necesitas " +"Seleccione el módulo que provee sub-páginas para esta pagina si necesitas " "personalizar la navegación." #: module/page/extensions/navigation.py:115 @@ -720,7 +728,7 @@ msgstr "Extensión de navegación" #: module/page/extensions/relatedpages.py:13 msgid "Select pages that should be listed as related content." -msgstr "Selecciona las páginas que se mostrarán como contenido relacionado." +msgstr "Seleccione las páginas que se mostrarán como contenido relacionado." #: module/page/extensions/relatedpages.py:20 msgid "Related pages" @@ -728,7 +736,7 @@ msgstr "Páginas relacionadas" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Sitio" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" @@ -764,7 +772,7 @@ msgstr "Títulos" #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " -msgstr "Por %(filter_title)s" +msgstr " Por %(filter_title)s" #: templates/admin/content/mediafile/init.html:9 msgid "Search" @@ -789,7 +797,7 @@ msgstr "Imposible de eliminar el elemento" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." msgstr "" -"Imposible de eliminar el elemento, porque es padre de al menos un elemento ." +"Imposible eliminar el elemento, porque es padre de al menos otro elemento ." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -797,17 +805,17 @@ msgstr "Cambiar la plantilla" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." -msgstr "¿Deas cambiar la plantilla?<br /> Todos los cambios se guardarán." +msgstr "¿Deseas cambiar la plantilla?<br />Todos los cambios se guardarán." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" "%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" "¿Deseas cambiar la plantilla? <br/>Todos los cambios se guardarán y el " -"contenido desde <strong>%(source_regions)s</strong> se moverá a <strong>" -"%(target_region)s</strong>" +"contenido desde <strong>%%(source_regions)s</strong> se moverá a <strong>" +"%%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -848,11 +856,11 @@ msgstr "Añadir nuevo elemento" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "" +msgstr "Añadir otro/a %(verbose_name)s" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" -msgstr "" +msgstr "Eliminar" #: templates/admin/feincms/fe_editor.html:40 msgid "Save" @@ -892,24 +900,24 @@ msgstr "Página inicial" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Recuperar los/as %(verbose_name)s eliminados/as" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Pulse el botón de guardar inferior para recuperar esta versión del objeto." #: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "" +msgstr "Historia" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Revertir %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Pulse el botón de guardar inferior para revertir a esta versión del objeto." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -933,36 +941,36 @@ msgstr "Editar en el sitio" #: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "" +msgstr "Añadir" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "" +msgstr "Añadir archivos de medios a la categoría" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "" +msgstr "Seleccionar categoría que aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" +msgstr "Los siguientes archivos de medios se añadirán a la categoría seleccionada:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "" +msgstr "Añadir a la categoría" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "Cancelar" #: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" -msgstr "Sube un archivo ZIP:" +msgstr "Subir varias archivos de medios en un archivo ZIP:" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "" +msgstr "Sobreescribir" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" From 28b0e77e23725389c3088d30750d20e78cf4dd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Fern=C3=A1ndez=20Nogueira?= <fonzzo@gmail.com> Date: Mon, 21 Jan 2013 14:52:50 +0100 Subject: [PATCH 0599/1590] Updated Spanish (es) translation .po file --- feincms/locale/es/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/locale/es/LC_MESSAGES/django.po b/feincms/locale/es/LC_MESSAGES/django.po index 5b8425fcb..d3978b9fc 100644 --- a/feincms/locale/es/LC_MESSAGES/django.po +++ b/feincms/locale/es/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2013-01-21 14:33+0200\n" +"PO-Revision-Date: 2013-01-21 14:52+0200\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: es\n" From dbcf8ecd659b88ab8068b5f383979ad619a4467e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Fern=C3=A1ndez=20Nogueira?= <fonso@kuruminoki.eu> Date: Mon, 21 Jan 2013 14:57:04 +0100 Subject: [PATCH 0600/1590] Updated Spanish (es) translation .po file --- feincms/locale/es/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/locale/es/LC_MESSAGES/django.po b/feincms/locale/es/LC_MESSAGES/django.po index d3978b9fc..9d17a6238 100644 --- a/feincms/locale/es/LC_MESSAGES/django.po +++ b/feincms/locale/es/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2013-01-21 14:52+0200\n" +"PO-Revision-Date: 2013-01-21 14:56+0200\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: es\n" From a1286a1c6b83837b0f02635f64bb8bfaaa653694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Fern=C3=A1ndez=20Nogueira?= <fonso@kuruminoki.eu> Date: Tue, 22 Jan 2013 12:47:24 +0100 Subject: [PATCH 0601/1590] compiled .mo file for Spanish (es) translation --- feincms/locale/es/LC_MESSAGES/django.mo | Bin 13508 -> 16126 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/feincms/locale/es/LC_MESSAGES/django.mo b/feincms/locale/es/LC_MESSAGES/django.mo index 23fccec1ad3790c61a738fcaa73016cf6b755971..2096da47a7eeeb40d1d3bcff30ce08ccaff9a7a0 100644 GIT binary patch literal 16126 zcmbW73z#KEb;k=>6qYy0Q-MZUc31Y^eaUNB7WN4XyX?3#Km>H@dvDK7@7~*e>FztT zv&NuC1>=KYg5ry0Ra6o|5lM8T5*S}7245tRsEC@x=oj_VMAQ$H{Qgzd_x3(`nEQQa ze*LJft~zz<)Tz_+-6Ln+V)#9dyZ|}vxyCHr$Cw3&>Z&onKGK+L;cwv4@T#MXc|PpI zBjB6hY4A39Fr0z=!LPz|;Wwe`J@k19JOk?aA*k|KKt11thrt`+{_s|)dTxV@;d}k{ zZ^Gwr{;22U@L0}&1ZP7vQuhynG}#;pSHn3lgj?VN@F930d<5#fkHJIW&)_lecW?|o zj}z7N3dkk%7C0BaAM#4`5Ih||4%MFnXw2d8XoxD!>F^*}hk9-Z>irF<c5a30ZwA$# zZLol^fwSNfQ1v|N&u1NH%&D9o2=!bIs{W<$1b6{_F}w<%32%bx-{+v(`v}xH{MeuW z1|HA(q5M(%=Rt<doC&3mb?`QLB~<%<1yxQjI|m#B)sMAM*EhhG@G2<1zXz)Q--qh= zkD==MC449R9aMX7#VGXNufPC44pra27?0X<7}R@Cgs8%t235~8C_Sz9_b-K1X*NNc zYC7;Ncmuo|eg>-i2`9SePlh_5?^%a>?^3AuT?jLH5j+X*gzC??pvK{GsOR_RrmoM1 zqwq+$8jiyi@Wb$R@TYJAEKYWIy#v-c{|0QreFI~bz%jTKz5~vOUx8}R6Hw#+KTz$Q zbqZ~RN5Ez9rBMBU8<d{zhO*lSq3q-_sCNDYs=i-B*~4%B{R3a<#^GovdzlY0ZL=Ke zy_Z8he>K#6YeJ1{;yDG?u2(^g+nb@vzssM$&+~4m@w?C8f6!n58k9aCgKF;&{rS&5 z{~M|uzlEw-gCHINb^UOEehgImPJ(LRe5iVtK)v^D&lR4RLfbzmy<F|j8~%I(sy`{z z^RM*00jmC+q5Az!sP}x(^TSZ>xZCqnQ2P7=)cAZCs-M4t@*De}=H7D@lz%-1s=lRA z<8cn$4{m^}_a#v8zXt045u61xsQXh;{dx^lzi#yBH$gpj3sk+g`TO@kwPUBh{$;5C zeh;etA49eG34gxd9Cv;=RQ)f2Dt{`}`)hE2cn;J!Er)vVS~v@C^w&qB?C=`6Kimpc z-*r&swn07jN~rd|9!fuN_xJCB`*VI5)cZdU)vwP$)%y*o_J1F$zMsK;;eWyX;S*5p z{T<YM4>;Y`e;7>nVI1H_uHQV@&8Np9Q`tNLHJ-=JbN;;sWha+I^|uLE!>y1hZaxY% z?q7v3f<J<K{;2tG{=Nw6{y01UUJup28=?HfTm1Q_J!hca^B|Pp_!`vvXHmJHKN2#v z&GX@<@O(H0-vDRBea>)tIT%V`$3v}mb;uMmE8sTRg3|YQATHGW3~GHjc!Be?E1}9? z1NHp%o^OR}$L;?7E_fm5_rrtXzBSkW!=U<kEIbgN2ycdS{ryiu)pI}8diEvAkeEl| zbKpKGN7oO48kghX3V1d=4^I30_d@mabMR33DAYRfACRFp`z>_!%!f=#b1qc5m%;bL zHar9#vB>dc_%hCGQ0;#sRQ)%@_3#651N<eF{#Gn@{TPAj=QZ#na16>$j$shz!K)#! zGOvYt|Hq;H_zaXDz6I6p??a8_lTdc>Tow)K<1mP6nq#2)u^g^}4LAWm1Xb>c7dsvY z_58_D{g?}nfHi;r0;vA4g{to-Q13kqBTzd}fO_r{sO!UU1YQlLhmSz%;YoNayyPrr z&p&{u#vFOJF{|JzxCPz-&xOB$G}SC1*ie72h3fx}Q0>1N%8qV@8t>cT`S9Q2i{Kn8 zVTm@wQ0ECe2)+ZVp4*}7xeFc+@AdaT4+%lc*P-nFr|>v<(2y&C8kD}yfU0jPRKG9q z=a)du>nq@~umd&TuY*U!o8Xb~c7Od7o)7rz4?*ekF{u9it3Uq*RC|Bz`M;je!N}F0 zL!jDqj6XjKs(o{z>RIaVUkKHoi=o;P!oy$zRnKdo>UlHN`)+}1|GS~=;sa3SKH=}* z@A*Zjem@LV{@?udpF`FE1l04-C0LPPIv&bzoCnp8mqXpZ4ju*n7^=RvLpx6Jc+T&I z($B+C?R><ae+R0cKk(Oo4yEs3L$&u%j6=^I>v<wnJ5PnGw+2=2BB<wvq2}KhRJk5h z{ntbF=S@)UeK%COyP(?nX()U6EL8c2q1yRvsQP~hRo{QYS?~#{=bnVmgZnLa?K}?Z z`bkjb=XfrJ(#yF}_B9OEuL-F4BvAUCgzDEDpxXC7sP=pe>b>_t)&E(~FGJ0PuS3=I z1E_j_0{4NNkV}y+@>j^dNQAVI3z6M_XH_nIfMd<^KS!8O{ohWG{t-F7f5jba_2=KN zTt_{2U#3fU`s?rZd^7wUk|2MC+>G>)hY<bdIM}~`!QYz@`Gf}%=}6=F0CElT9z=de zHt-olKk4^k<PM~c%pm&7@5nd426-LwKICP{-y!;a+QHllZ}G>E!*?QAAumKOLq3b> z*FZjLkMN(KB|gf*X5?Dr>&Vv-T%`T|J%4e__V?GG!ehukAk)b02vg7uBOgcp8F?e} zPsrO5{jNveWslridXYaC{=^^OUAcy7n3p48^4CJoSHL$Q-|^?TWD_HrH?KzCipbVJ zf*go^50S0uw*^^?q&ngEhltjbb%^H2dgO!1TaXiw0(k+VUlX~_9=SjN0`@~Dkwxy3 z`2)BHX(Oj00ixe5MDt0%OOPBnR44p2AMUY7gFn}Cco*_9WC;07<h#g1M86vHd}I_^ zfZUJh_YLF}<YZ(e@+w5@<9m@C5&bm3JIG?>4CJNAhmpC6e8@(m{9REVz-`FG$OJMU zS%&EMXUGlq$o+YVKb{RA@yAo}ZOC?i{uTH|<Vxgn<W@xf;!TKte~Wy`9^tFuE0NXy zd>&kayxyOm3O|8-6B+l{{sw-^AAbuTj6CYkkMn#7d@XX6KhNOjkwcI#_-psUgZ%NA z;hD&Z$XAgIkUvGr-wqwj4)*e!Gq0I;I#E(=?&VRIgq>)99^_%%3eqGP+{}B8PF!qm zg$4JQHL_sg@;$0E!OCeK8H?LRlx;5JqOH2jpps_VOA0ReH|BLSrxj2<%7eJmO|v3u znK^kd5#~W7ijts{PDZVuNP{p)qN$*p=5Z0HN!`p#(x4f3bu!<qXtg91YGiRV7DU^c zQPwSjyw~Z3S-d??#)D!a;;l(RKZA6P(>M>h;doScPbMh^GTJ^FWsNkCHak7oo6U*1 z-Li%4X(wvMp>H%TYod_xG@G{f)X2DqI`$-w+EJ4p1yA?HE;WpyHnXDLmh@XoL*s<T zQ7^j6($1jqK|B_W$CD8XS<!37saY9~rCDTF#z{zvR`%LkgI>3thSJSd>xONshs>(5 zIYC{QZ(7e`(u~>y8VFjnxQJX2_Pn%!F=>Vv2?YYHzRYVgEP{3v=4dvF0;fr7p<dR@ zC}vaYKrj^-6G1B;8;k6-8v3A^?nc49u;2*>4TTJfhm1(tZf%aX$!hGwx`dkDrTM(U ztAEu*n2blkoZR>$RoCXOS(UciVV7nXS){XMEY473x@&j6ZFmJojJIte21kGMAnX-s zCoJM-*lte`2BaR0y7p#qix<eM8qq{J8K=E$K@eh;dD`h)9tz1KnnX*&B&TthuUXB7 zS|iLEk#4Wij`IoZ)vR_y(YK*pEpv0X-OIxE{G4)mGmGs+kX^?eY}%}5@@hPLNh`|o zB22KsbW+nGPVyq_HQgjy(_$c*<m#ibC)IYXakI#*+16DBR(TvVNrQf?s+P^1-5z(X ziJ7(ZvX?QL*IHL#*0#fZ!dyJMVSO+fx2E0EWY~^zC+HyPW@)R}L<4daauKayD$EjE zoY#Y4*;W)}(PYf@(nRic<%U}QDbk4A=@g2W@!N}W(&O17s_R5~j!JS=bumN4pS;j) zy_jJ!>&6p3p(<_LDlIBsZ`N6ju1oNZg`CikS%+nL+hKTn%_grH>tPmkvpxzZqd<0y zjmXPzk`&o=kWZvNoCsqv9fYW#Qfe&oqI}5Oj(d_j_OV!QF|oCDGe(wr+8BAyx~&ay zGfVSytOztvZ8JC@PN$-5IE|B{a`DPEYnjV1%yFl2W>l2qvcJnvYUz)I4()41GF%4l zGQ68x8gSH{#7VbT*a3E4$85AtGqu*2n~n6wPXlxsX5&#IA5#xjMyN@8Ru#>5kC}q; z=M!`f&mko>qVYJ<a0fCqe=*_^B|2vl2JMu&=PDf4JPUCm&4T%c!?BelgWjnY7A!gV ze6F6M18SaiLS}gN+Mty-ds_6&Fl7R}RB1$5LDDIP8efyN(y4kd!g?5B+O9-nnt>k+ zd+nmmgK`jNIK}U+a%wWe8Ma^>lgkhqy`sRnoq5vxENaTPQGoVyApN`52)EhTLU*Y4 znX2G9>m{F|5=|DfX=EfAix|rCAUB&L>%p4NU6xMrg1{~5cHyzNP%uNLZZIIIvs^r_ zgItCeNt5yAbLPy;@pR2-bH)g!3Da!ZLVr(Qv%h{<9&nc7AE=bC|9_g+f2gu_T|h-n z&+ekU3QDUk>zizA-9)9dmI=4QOFwEfuzKF}$+$TYj52%72&yq7QJ6I+JeahYF+<6O z=)~Kddmph;KtD{d!A!T?o*v>M#RoR9kj-HA-b*k6Sq9W33@`Jo^ZKusk7?R;@R}^3 zc+bhWrP)*3yftNOAesW2Mbl{y??siEVY7!1q=C-!4W^CiPFiMU0w3S(6}gV4%!pQp zks|E|S|WIh8L^=t7`Q&?F)HqRurlb4xOG&lFljzB@mW5IQl9q7{^;T*v12M84aXUP zaacMZtBC&EjWSy?ldw=(jo~P!zBNAu_Sfh##9|n;nA-3;l~r*Nnl{sJ?9{1|U|}FE zXxi1?SrTvHI-v&cp)IRmI@mD_<<b=zFR<rhL?<cUX55zYv#!^$CDcq+(l0X5s-hu+ z#L`zwRjR$eGMD-uvNdFQrLj0-1)>$@>Y2;L)xDTSk^r$4PS=AKf%go4;c<S?zAH`W zA}^eb^SFW8;k)$82?aRT%tFPl_F95+t>f`8Q$Kh!j@ZUhZS>TdW{ucNjE_$ZlX6j1 zJ<nL!MVNjWtvsQ=DU6aISIfqugbr#R4Qw1mrTztj*~a1$CtIb%P!px-(M#%>L@_CU zTT!|oi0e^(D3~aU?$E-8Q&UrQU$D*+xo|2hniCgHp1-}bWpUQszIxMDi(HS(LF#5v zm$@}C7{83Lob=;2->heRWNS1%#cFPSMEQ)3E}Z$%hjz+r^#eE&qXT@@v>BDr<>m_Y zhrcZQjG&GEuJopqvtsuri(MvCwg=XC5c#4YlzOcXQlr+jm`c>#+DNwrVFRC8H!sD> zw9;g5!8Bp{Q}HBHc%;y!8)cn1*OF%^HZxIcKV#-rK2z>b*uL2yb1Y<Y&?1J*cfW-e zag6@D+cyT)(nO)^F+rA*k?=xGooZv6U=l&0=^x^ViRf(@UO6t;y6XM%8dXiwuuv1A z;umt$AU@e@{GJqAcSi(Q9!{Gwmf|2OXqfD@v&#vE-8Q78a}<L!c1kMKoyIjy6vq1- zN5v8fiw%E5Q?V;UAd?vB+e97OZlXlZZ^457a&9?o{H_`L$S^l!Wf-r0nz5U;I2lXb zQO*M5j<kWZM?687!os+1i2a)z3~@03IP-g1!_d1qY|5yX1H7g8Po^D>6-E=&bi!?Q z=i|-516B^JBk>fM^U8G{7x=ru)N>d7#Nu|!7S$Vu)2Y${X3z_4v<#o|{6>2%J1v@q ziOE)-HAsP;jfS<&mXor7{DA5_=YowO*`>ybDRUbJS5f0S)nMnPJ^0!kTm)~&x_UwJ z^57!jb<5b>I%2AuEL5OxQy|sj+?1;#4v=FT{$vVs>>TMIQO+7&&iaY18PDA0?cTT{ z@=*M0^68F-j5pdo7qT>C|K?zvKjpT(Jm|M+_X{e^B(*D$`x_9P4~~3T+U|7{Q<;hc z)YVgJk$LvI#yWEM*ZO;Rm;<+-*~qpgB@Ab&I#XNMs$Jot^r2vF6ep`TjLhB?$vf3H z<l}Lxwz4;#*GAK!VD|9F(VE@dqng@krr}VqWYOX!wMFOD7M~R?K4)n0*=H<TvS<+n zYs8kkvRZCwZPDV|lEuN|7Z06zmMgcOsZbmBd4e<>3O0}-nTT<Gmqx^f$wb=T9xUr@ zy>N_%O+;}~Z%!<qz25H+Yok%v84A{~xa^|KS6s9vShjxsh3&YWX5)i0LqU|!-mq@N znn5QQ*B8xR<xHeDirR*(4J@=4dY&SKj3wgy%SYGN&KZ<b8_DO?)+9~ljkewAG~#0R zuuW0a*5VQJp&)S?i~Rg0=LPQY{CP=m%K5?K`Lk_aa*!mfq#;}JmNbakHm-CzO6=@e zq#=h{y?4(;n!y_?X-Iq^DZ-RU%Pk~fD`jb6fw2onn!9u)%VaCHITR3*S0NwSizY*x zk!;2@_atUsj-P8s)6Bw<l;q6aA)%%t2@4)*XuDrJ9s3O7C@IRACu}F(+|-NMAh)S| zW{2WWa(k{aGHY47Q28%hOLaG6@4J`yXM%}%OW1#|?2GD^|D=b+2w}M=nYnXNRJ~GT zBJGXSehqCs;x$sK#YUS=EZJ)9sp{PQIw`AeZ|08NjHW2t{?!-{x=%F98WFXqRWHNb ztIDv6&K0<^+~qmrR2!0*aE*avdhDg0M43H8OxFP=LWhh(Q7$)0h0fgJ)1YBSwnu(g zi@RRjW*bK)Rjuo*WKd#nw-;a$*>ycN8VA^72TeW1*r*c~Y5@B+1vaNbVyoMWD3qrd zh+UD?7nGqU7jf6BplmwJl1-eFFD1RBAyWOjKFVX&q^YlIZ%I=P{06_&F<;1>hMh)C ze`S2E$pv9ysPrk>Q>TTQ9T*<zVwXcz*q?=aSJRs6fU;9lpc$uLCv@5ku!}Zlb||kZ zi;Kwismfh@B!7oS><5BS^F@KW=7dx`KC_cyv_6Ze<1(z70s<0>Ze|WEtI9xYnzBK% z570xhM-!o0Q;snvzEDx+E|aUDXLTE^($veWtE-Y`P@N5S$fhyCD9+Alt|}ZLEYnt< z-Gptr&9q9LiR{X%rMy&a^_p#*HJO7h|B6je+Uwt?VKq=sIWOtEpOz>t-Oc>VtT{P~ zR%&y!Y!UWI(ykAgQcBU5-E6xosZG}6mj}685^p&!G?3dJ3n%%DuZwe;#$ad^?DeQm z@03Q+4(6lmdV*2MJcPwDZMdc3B!wHY>g|%j-Pk1aMoTZYN!&Oz!_GxgMcj<TwoB-i zda;dCb=6)d&+Br!iE&9?id(NYge^F?S6Vdf)a;qLV_RHcStBu4Kz&>27u!}QNHbM0 z7;mhN-mt+5wcp8RcDTsa_7H21iFq>iN2~3#)|x}CnT9oI?$o5f<OzMtnsgx5k<;Ou zL!fU1^-3!D+2?z)AtiZb_o#vJH5zw=Numcw)uN%eMZdaOCD>1MbjYrW^jK3%6Vshz z+-QKzXxyB+r)pEw?zKQpIHM<NSN4aCwtiNL+ITXp2dg7?)^4&!85M-V+=X-HAIWbg z&A5w)AREvQ#%$h&gJzH1qkSvY+L&FhRi!o^To2X^v>EC(p<CK2eN~NiqVSZpE@_%D zqUP61mj02d?`6B>Qp0ILqS%bi+*$P6eT(%5=ZB0WF1n!`@^J2*tu(6#&Q!>;VctF5 zC`K=%pb%SNreonMRT7ys!mLRq@x|)dK-*@x*GAbqLW0|mAgTYXg}wG?jBN%9tsb_= zb-Pj$9F#-ewtH*Y?(b0<&lh+b>{{#Y-fOed+f8QYW0hnMNHVi!j9R%pdf+}5dcNGS z#_qYQ*nIQC<u(GagJTQf&FHf4rEGIr{qH+>w47sUm0a>uC!eWD8yPzlt50Cbe3#f; z_W9}C>(b-T(B8Uv;J#IEZL~p;j}Qj_vy38airNp_UKgJE_yD&u5hAfJk&hm?^VqtK zzT<Q0Vdv^8R4!&dd(9~Bx}41?+G0z^hlseDnv0w@@tHVphMC#uv(~P)*0MS&-^!dz zZp`e=iECP+%Rk#!5~jE`hm2Q2PiWIAnNMw74`BUTIn!(*J2HGD(2TGKZ@nyzN|CR! z-L5-wxTwpnV|E&JX6_-|o!UB-@s0?5Dzn(fA~seG6*uE{UG^z1FhV9s&Vp!XqMUZc zLDV(>2z$(mBHThix`8h`S`SHl6I+fdZDoT%yq=Bped!VUYh5R<aIj2NS4AIhVzPUW zx>eRG(51!83M0O)JZ+WMjXkS6=g5xSs#dkAO6~N%h#9;>p@1AK&1Igk{`!T<X9w(P z5?$*%xC_{P5<N8!?6`<fh1mNPEO3|UDovxyG87x6)G>kyHX!8C6%DZ5DH`y;6@M1b z+<^v^C1(4xo?CqW#KQ&cnLCq6o=JYeJJE9O2;23*Ek3T4e2FzNti%_k#p~r`;_;qB zF{;_iW`U;pCDE>qYFWk1D_fpW5d&eQ^L%PlHNx?`kxAu0wJG4g9>RKHBW#-B7WlFU zd5T?!OgRd(^6#Pz#=`EFG%hry|B8WA>9?TYFUC~!K%+Tr{kYa1HWay4wU*sd*Hjlz z5(Ph1aW$M>%N`Gm%BO3Ptd6N!!)Sd5ZLG{KpMxhlsu+%o^ofQD2K23!buUVo_b6V+ ztc7H#)nD?-qc#^GT%lCF3oxTC${>+*`8{&+BX%LMAD`uA`hg~mt)>FK>(gLG3MQ-% z(h{=QC-sd^D?j}vAFQaS*(SuY%EzZ+y_sLt8@(nwN;j@sv{GN!)81>;MFFJbZI8_r z=z>CSOMrXP0?by_2b6<}XZ2SJjrh+1yX8!RxjrA*O6S_$Wh>6R`kx%x4p!$<@Eq8z zyp8F++ax*c;s-u_kjP`(u^z**iTFzRUv5Kfs-EuyGxyl^{EETGx_kyD+kMBJTow7$ z%D`lwxgrxf&+k+Bsm%ov8oK;F!6eD~{;tkcLj*fZ_IA$)e}0v+jZvb|Iw!@d%us1d zyMLR`N2lbVZ9>NkJOKIk{-Vcw2f?vY-@Ue!Ds`(xOfGWe{mb_K{p<ZEo6-v?hOAs= z>)(IEE{?pdn)tVVlX#0=tbHN&=K4eqm{knFp??f=m%;`soBag9x)#;!R{%Tpx#)H; zd3m7xzuS0n;QmDfb@)EJ4Wl1Dqi+FhdG;7q61^Q<sMSMRcDGE1@z={Q2C4gGkN{Qz zzT2ri8p(<;F=bK++t7Bxxc!lt+1ch3=I*Z1#M`gK%M&kClbnl5W_GfOkj9(Yu`TXk zK)bKceQR*xcDr01q+Yk$_DeW>VZipRr0iMcsXcs*u~&BW8-t-NKR>v!OVSRRAq~q@ z?B(pnjn4)+a+YwLaoA<sWxTVm7@9O&UiH-H2<=6b_(_ejVD9yOi)5WGKTJ3?=+5j^ zVg(Z~ZP0rk_n<$?^vRqLQhm=fI0~W!n^qo6PPv)&Xny}3Z>kIZuM^J7Leoey1!wv+ z;Nw_(NF+>CWcDng<aPKu;hJF&>{ir%rwDWYy^Q|(Si}B1fD1T7`<cT3#r%9!gkJio zu>O(8w%^i0fn6@U&lfl@=jBVP4BF>o8m}7cEp^Uzr<v+=26rk!6aTeVp4xtBDq*}? Y+z5?ZE4_uQYJb6D@NI)TH9rvl2MT+?NdN!< delta 5541 zcmY+`33L?o0mt$GavN@taD-z51j4al6B3RP6$C_RkjSARAWk+zvas0=yBi={x*~Fj zsNg85pa@!Tq!<*eS_H(iDn741tEiN=zH0T=Dv$TH+V5{?&@hi*J~Olbd;YV_Ppe*v zq)&8dai`&UmGmYHS{c(mV9btox@*kwPR3k=?_f79>TFC7UWx;;3RUzb9E)4A10MJ9 ze~K-+{tBDpw^)d$z58jC-^CdEGzGpT*q!S#%);5oKeLEGlQ4m8@Bp5NFJec09oyqa zn2lfHV*DBV;o`1dJL^yrxf=(Wv@v@*(F{I7CTaeLt?@f-i$9_|Y;(Rh(9WnC^*{}v zFQzabTj0IEyKw;552MPzfoks^?1i6TG5wn}oRnaYVQD5|<d#XImU08C;ccja?eIT; z5PNd{ENTMpqE_HDybr(j@8805jN$qo)JngLD*q9t)!;ul(G0&q&FBo?h0S;l#kd_= z1all!@f50~|Dg85&!~DiJ-mVDp*k9hnrR`9!g8FCYfuyVv<K_2il_V=U!ywsFRB4e zPb<(GwUpVYilwN5Uxbrz3a-UXI2^mst2Wt1Sb)ngjQ3*^wqVpFadZyrua1^-L(eFI z8o)}Nf@^UqzKI$@cU}>7JPuWFBI=n=L#@yis7JR1SwxdYwYwEnZwG2qKZsiKy(*xS zgQ$)Vqn7q9RE3ZI>r=kpqE^iG@jlN&mG6RD84ER_Jpa1TcNA(M<52BR@J&zkKe*h# zaV2Vmi%<hwf@(O4>UgE^4ZfQ&Geh4UsFm4`8rY+#dIx+DquPA~nQ+>?$B8=l-1i@- z0etCu8nu*xzTWpj57Z1psMoa&)zNh1JH^aLwO5OJ6bWpO>rw6Aj2ggJY^V2sCnu`# zgkNAEYDUkaW^%;8ehpReZB)a5@jw4JY9QbF_gnV!X50()NC%<@T<Bk4;9pO}R%t%C zf)g##LR7=msFD5_d4<h-)PU|qJ-Y``19==Z@csV%XHjp<VO06!s0n<4D)$Mh-bvJe zzr?hb>_@*q2g|G26*Zuqr~wT?H9Q72qbaBcXJa#*hw5+vYT%Wqj%!ivr|?F8Q`X@O zuG{wa+MVB@^=H*g9XAH!ZK!8?04L!w<h#XW@$P94^heELEULqcQSbMq{`CsqRj8F( zgPOq2sDa;)xwr?*@$CU=Z^XR^dIbifDikBX8)hmp2D1QHVjA=C3~FY5x!{d7Aym2P zsCsq2YfuB;>R<0f4df}*01u@(Y01ees3m_Bx8R4U0+B)9Z^AO<pIObHR`>|&w_-19 z1rOl_Jb~lTVmbBs0@Q?}s7JUO)!$}pjp?nN@U3a?L;5raQ58?1DtwJ=@qegCvnHR7 zid#?(eS_-Yd(_OchIljXgPPDFd;&u_5kEnSn%tq8_S0q>C)(xnkX1Et%)&dcHSWY# z_%JdC^CV8j53mM%5A!}>>$?e6&qY0=?f(5es9nDwN8mARsrUbTPO`Z118P&W8t(o2 z%|dOiuP}r;L2m}-xP<G?I2M0E{g{+cxD7^715RK&Y(PDlb!g+ONEI`bQM93dGnW%p zu(2)HAip;zh1y)3ksm~}2UYH6)C}K5m46>KfzSQxuTXEx8Pwa;k<sf>3`VVVA?i_0 z!L&ZO$}dpme-J}G+tsKUtoN_)Kn>s?-(9|spk}@oHL!#J^^2$hzJ_Y&egE^5s0sZm z#QJL_%?rIvmyK#@5UQgQr~!_`&Nv?R`ApR3^L;B(GmfCjU+>@Fh#k4!f}L>}TG)uW z_+BCFuK}F)3!GQv{f_6L8XSS@=n~XhG99%t)u@@)`q%ZS8D8h#-+)@`&8PuCgsQjK z_i5BXpG$M1hL52Neu}F21$MxnPzBqw!_+}{)QkqAW>kzScL{2sb5MI>0jiy9RJ~QG zy|58A@ZG5X(vNYX4jQoqzJO}z2<p9l4K?x;{{2&^@?ZLXk6NjpQ5|F#d*usI9Tj62 zEJICn25P_&WMFBtk`r~j7S-`a-!0gQ>$^}5J&I~*9|ll|zAtn<Me0eCq==5$<S}xH zyh`+~sN*4`uWIk$`O}_xoU9{T$SU$6xr*!}>U0^ol<3$-o*{#D!Er6Qo4i7POO}$Y z<T5gygvnu|9p9YXL2f6*iCI9(NPAsyEF$NVo5{UI$0qVeQcJY-bI6@UM~qxT9HOt+ zd&mZoIoy36x-vn&io9zR#aqaq{A=wH?Siw%<(yRe7Z>1uawB<?+)8x(#=~sHmk7_@ zY$x-{5HggkAvchR^?-F8B?mKS#;m|$BuG}1F+|5&kIdg*{C$>ONUkJL6CHmb^9bK; zng7VI$I+zeaT^zUHFjri(*G1rj*$X#b>^n`o2k=_$phqfy5Mj<GQTuBy^lOX4v=d| zck(>Bj#LsIY~x>!CBK~cC*J&xS<W?Idzp8o4xb|vNNaKz*+<$E9Wy-4qj&{rByn;- zX?ncKh2E)I{!MMBu4FuUf=njq7W~oClH`(^q=ED!r6h~!xX2^(w*!A`$WD@<x#RuW z>!0^&a&HIc7Fp=uE5s`Q9MYMeuxXriBu7Xyl0$TiB`e7&QbBYKAe%`ZnM9_NR^%p9 zPPC%GC)bmgNhe~H5)vV2j~6(ZYuwXawz)gI7P}vI9oIcv6Ny$?b#}F5CR9~fF=vGp zNjbIdw)0oG-MU@rzSV7ikD5qTl@qhV@wx^pzSv6DM3R{r?zP#&+>_aJ-OBFU-IhJR zYd1Z<+%fuNrQ+_H9v8S%d+xct*FyL2y%xLWIU#pd&SJMk@0{$qs2z4PO;~yPsraIV zqdV@H-evBsy?5oN;&s;Ksz@plt2VRhD{CVuGpnIC8i_4+yrH_E^%><Z?K`>g+rA$M z+%uMwuCeLVYlbp;$pUL$yxyv{8yIzrhUy*5@mgf~junfq2-@LPgi4yaRp~_ID+<in zIx3ne$CM*}pJ&UcT0E9CUUg&F)kP!W#*Y2V1C5mf-U|%3^1}=>l8PsWm_#I8W2Kyx zsbrJWCIuQt=Zy@cL&4D4U}1?>SX^2(c37w=6w0cY5uE8Pk0j|SILS^qrB+d>FjKB5 z#A#_!@i4AKS><*z6`Y;0W67vZkENC!OT}Xm%Z|nytTJ1Sx9gJ8f|!%KkkYa0dZrtk z?bx-YmXox~>Jsrz4J^@kJ7#m<P!Nk==(Zg^zhZ8%BCcr!&sHk6X4ToTNU|pDmyc$} z>l0yTVvU_hI;m2tKD9VF=GRXr#_MCLL<99ICQQA|y>0MJ_vGMWH<&-pt;?V6zMr4t z<_ziRriaYw>sa+M%TBNtm&dKErdE`iIWx;GZ8<w!<G8(s2Hm`&-QD>^`?jZ`6Lo4G z=4ln&KJ4>cs@mF`5!;G~>!T^#s^VEEvF_-u>PXCXKOPox7YujYX2C;^uLt`D+G~d< zGW#@P+3ptwmj~kR)gy}B$487Th}u?+y;N<7BS#x!R)ZCdCoM*kRI^b#X(j6`gMQ1& z0=IAIrsfGJ=uRrUksY4no+`{{m-lR8jvSig<`ne{SZ--ix%*7ffZUmmQ_D8L)=tpQ z*}<K&|IZXvxY3c51Gf9r$a*(e+_O`KHwBhL6{~EwXUWCx-jeC=v{5GlvBn{zM+e*u zV-}?+gzZYk#t;*~_M*3-qTZ?EIr}dGUF(_Jv8uSnu#C6Du8AjXZG|Rd%4}`hvX|8# z-DA=4l6Zmf8_HBaX98OK-VE*B;&wR9-gWevG#(!N=YV_XxCfY5X<2T-Zd_QlB2Z%S ba>Sdw3r6n=YpvVKb1s?`YW(X30|NgCw4y$l From 51209557301c098c8b93c75daae9c79b34a30a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Ba=CC=88chler?= <sb@feinheit.ch> Date: Fri, 25 Jan 2013 17:26:38 +0100 Subject: [PATCH 0602/1590] only process fieldset if they are not customized --- feincms/templatetags/feincms_admin_tags.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py index dd306e30c..702ad6422 100644 --- a/feincms/templatetags/feincms_admin_tags.py +++ b/feincms/templatetags/feincms_admin_tags.py @@ -13,6 +13,9 @@ def post_process_fieldsets(fieldset): Additionally, it ensures that dynamically added fields (i.e. ``ApplicationContent``'s ``admin_fields`` option) are shown. """ + # abort if fieldset is customized + if fieldset.model_admin.fieldsets: + return fieldset fields_to_include = set(fieldset.form.fields.keys()) for f in ('id', 'DELETE', 'ORDER'): From de69b9201f0a1e3bb8fe6d59599dfb25d28767b7 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Tue, 5 Feb 2013 16:27:05 +0100 Subject: [PATCH 0603/1590] Update docs/contenttypes.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note additional arguments for ImageContent. --- docs/contenttypes.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 57d7322fb..bbef78696 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -330,17 +330,27 @@ Contact form content Simple contact form. Also serves as an example how forms might be used inside content types. - -Inline files and images ------------------------ +Inline files +------------ .. module:: feincms.content.file.models .. class:: FileContent() + +Simple content types holding just a file. +You should probably use the MediaFileContent though. + +Inline images +------------- .. module:: feincms.content.image.models .. class:: ImageContent() -These are simple content types holding just a file or an image with a +Simple content types holding just an image with a position. You should probably use the MediaFileContent though. +Additional arguments for :func:`~feincms.models.Base.create_content_type`: + +* ``POSITION_CHOICES`` (mandatory) + +* ``FORMAT_CHOICES`` Media library integration ------------------------- From 5632c1c372578e92464279172db3077261cba2f9 Mon Sep 17 00:00:00 2001 From: Greg Turner <greg@interaction.net.au> Date: Fri, 15 Feb 2013 10:46:37 +1100 Subject: [PATCH 0604/1590] Revert commit 3ceb1a37d8927cb6e1e1768eb8452c9b55d950d4. The attempt at elegance caused a bug where reverse relations didn't always end up cached. --- feincms/__init__.py | 4 ++-- feincms/models.py | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 1a9d5d1a8..7fb46bea6 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -23,7 +23,7 @@ def __getattr__(self, attr): COMPLETELY_LOADED = False -def ensure_completely_loaded(): +def ensure_completely_loaded(force=False): """ This method ensures all models are completely loaded @@ -36,7 +36,7 @@ def ensure_completely_loaded(): """ global COMPLETELY_LOADED - if COMPLETELY_LOADED: + if COMPLETELY_LOADED and not force: return True # Ensure meta information concerning related fields is up-to-date. diff --git a/feincms/models.py b/feincms/models.py index 7ed18a53e..47cacced6 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -729,10 +729,7 @@ class Meta(feincms_content_base.Meta): for key, includes in model.feincms_item_editor_includes.items(): cls.feincms_item_editor_includes.setdefault(key, set()).update(includes) - # since this content type is potentially being added after cls is - # loaded by Django, we will reload the cls's related objects cache. - # See issue #323. - cls._meta._fill_related_objects_cache() + ensure_completely_loaded(force=True) return new_type @property From 4d66eb7fb66709291fb01750f790441c5af79577 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 15 Feb 2013 09:06:10 +0100 Subject: [PATCH 0605/1590] Fix #386: Do not crash in feincms_nav if no extensions registered --- feincms/module/page/templatetags/feincms_page_tags.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index f7ac17a7c..86fc05123 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -87,8 +87,8 @@ def _filter(iterable): queryset = _filter(queryset) - if any((ext in feincms_page._feincms_extensions for ext in ( - 'navigation', 'feincms.module.page.extensions.navigation'))): + if any((ext in getattr(feincms_page, '_feincms_extensions', []) for ext + in ('navigation', 'feincms.module.page.extensions.navigation'))): # Filter out children of nodes which have a navigation extension extended_node_rght = [] # mptt node right value From e2e4e229c28e106b46f84785f24898fec15aa299 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 15 Feb 2013 10:08:54 +0100 Subject: [PATCH 0606/1590] Start to abstractify Page into a BasePage so that it can be safely subclassed. Note: Naive reusing the PageAdmin/PageAdminForm with your Page subclasses will not work due to extensions fiddling with the admin classes. Needs more work on that front. Refs #241. --- feincms/module/page/models.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index d0c93d74a..f9118de6d 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -160,7 +160,7 @@ def for_request(self, request, raise404=False, best_match=False, PageManager.add_to_active_filters(Q(active=True)) # ------------------------------------------------------------------------ -class Page(create_base_model(MPTTModel), ContentModelMixin): +class BasePage(create_base_model(MPTTModel), ContentModelMixin): active = models.BooleanField(_('active'), default=True) # structure and navigation @@ -183,8 +183,7 @@ class Page(create_base_model(MPTTModel), ContentModelMixin): class Meta: ordering = ['tree_id', 'lft'] - verbose_name = _('page') - verbose_name_plural = _('pages') + abstract = True objects = PageManager() @@ -199,7 +198,7 @@ def is_active(self): if not self.pk: return False - pages = Page.objects.active().filter(tree_id=self.tree_id, lft__lte=self.lft, rght__gte=self.rght) + pages = self.__class__.objects.active().filter(tree_id=self.tree_id, lft__lte=self.lft, rght__gte=self.rght) return pages.count() > self.level is_active.short_description = _('is active') @@ -224,7 +223,7 @@ def short_title(self): short_title.short_description = _('title') def __init__(self, *args, **kwargs): - super(Page, self).__init__(*args, **kwargs) + super(BasePage, self).__init__(*args, **kwargs) # Cache a copy of the loaded _cached_url value so we can reliably # determine whether it has been changed in the save handler: self._original_cached_url = self._cached_url @@ -248,7 +247,7 @@ def save(self, *args, **kwargs): self._cached_url = u'%s%s/' % (self.parent._cached_url, self.slug) cached_page_urls[self.id] = self._cached_url - super(Page, self).save(*args, **kwargs) + super(BasePage, self).save(*args, **kwargs) # Okay, we have changed the page -- remove the old stale entry from the cache self.invalidate_cache() @@ -272,12 +271,12 @@ def save(self, *args, **kwargs): page.slug) cached_page_urls[page.id] = page._cached_url - super(Page, page).save() # do not recurse + super(BasePage, page).save() # do not recurse save.alters_data = True @commit_on_success def delete(self, *args, **kwargs): - super(Page, self).delete(*args, **kwargs) + super(BasePage, self).delete(*args, **kwargs) self.invalidate_cache() delete.alters_data = True @@ -362,9 +361,16 @@ def get_redirect_to_target(self, request): return self.redirect_to - @staticmethod - def path_to_cache_key(path): - return path_to_cache_key(path.strip('/'), prefix="PAGE-FOR-URL") + @classmethod + def path_to_cache_key(cls, path): + prefix = "%s-FOR-URL" % cls.__name__.upper() + return path_to_cache_key(path.strip('/'), prefix=prefix) + +class Page(BasePage): + class Meta: + ordering = ['tree_id', 'lft'] + verbose_name = _('page') + verbose_name_plural = _('pages') # ------------------------------------------------------------------------ # Our default request processors From 8f0b7563b6bd6960db1e8158d67198cc1e0babf8 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 15 Feb 2013 15:31:37 +0100 Subject: [PATCH 0607/1590] Move out PageManager into a BasePageManager. Make sure that ActiveAwareContentManagerMixin does keep its data per-class (and not shared amongst subclasses). Move registration of default Page request processors into own method so we can reuse that for other BasePage subclasses. Refs #241. --- feincms/module/page/models.py | 39 +++++++++++++++++++++-------------- feincms/utils/managers.py | 18 +++++++++------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index f9118de6d..a15f06689 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -30,7 +30,7 @@ # ------------------------------------------------------------------------ -class PageManager(models.Manager, ActiveAwareContentManagerMixin): +class BasePageManager(models.Manager, ActiveAwareContentManagerMixin): """ The page manager. Only adds new methods, does not modify standard Django manager behavior in any way. @@ -156,6 +156,9 @@ def for_request(self, request, raise404=False, best_match=False, return request._feincms_page +# ------------------------------------------------------------------------ +class PageManager(BasePageManager): + pass PageManager.add_to_active_filters(Q(active=True)) @@ -366,27 +369,31 @@ def path_to_cache_key(cls, path): prefix = "%s-FOR-URL" % cls.__name__.upper() return path_to_cache_key(path.strip('/'), prefix=prefix) + @classmethod + def register_default_processors(cls, frontend_editing=False): + """ + Register our default request processors for the out-of-the-box + Page experience. + """ + cls.register_request_processor(processors.redirect_request_processor, + key='redirect') + cls.register_request_processor(processors.extra_context_request_processor, + key='extra_context') + + if frontend_editing: + cls.register_request_processor(processors.frontendediting_request_processor, + key='frontend_editing') + cls.register_response_processor(processors.frontendediting_response_processor, + key='frontend_editing') + +# ------------------------------------------------------------------------ class Page(BasePage): class Meta: ordering = ['tree_id', 'lft'] verbose_name = _('page') verbose_name_plural = _('pages') -# ------------------------------------------------------------------------ -# Our default request processors - -Page.register_request_processor(processors.redirect_request_processor, - key='redirect') -Page.register_request_processor(processors.extra_context_request_processor, - key='extra_context') - -if settings.FEINCMS_FRONTEND_EDITING: - Page.register_request_processor( - processors.frontendediting_request_processor, - key='frontend_editing') - Page.register_response_processor( - processors.frontendediting_response_processor, - key='frontend_editing') +Page.register_default_processors(frontend_editing=settings.FEINCMS_FRONTEND_EDITING) signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) diff --git a/feincms/utils/managers.py b/feincms/utils/managers.py index 4adee3197..dd25e4042 100644 --- a/feincms/utils/managers.py +++ b/feincms/utils/managers.py @@ -11,19 +11,21 @@ class ActiveAwareContentManagerMixin(object): # A dict of filters which are used to determine whether a page is active or not. # Extended for example in the datepublisher extension (date-based publishing and - # un-publishing of pages) - active_filters = {} + # un-publishing of pages). This will be set in add_to_active_filters() below, + # so we won't share the same dict for derived managers, do not replace with {} here! + active_filters = None @classmethod def apply_active_filters(cls, queryset): """ Apply all filters defined to the queryset passed and return the result. """ - for filt in cls.active_filters.values(): - if callable(filt): - queryset = filt(queryset) - else: - queryset = queryset.filter(filt) + if cls.active_filters is not None: + for filt in cls.active_filters.values() or (): + if callable(filt): + queryset = filt(queryset) + else: + queryset = queryset.filter(filt) return queryset @@ -37,7 +39,7 @@ def add_to_active_filters(cls, filter, key=None): If a filter with the given `key` already exists, the new filter replaces the old. """ - if not cls.active_filters: + if cls.active_filters is None: cls.active_filters = {} if key is None: key = filter From e25890c2567e7e6bdfca4c9b4503e584d1266177 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Sat, 16 Feb 2013 00:07:37 +0100 Subject: [PATCH 0608/1590] Update german translations. --- feincms/locale/de/LC_MESSAGES/django.mo | Bin 14585 -> 15148 bytes feincms/locale/de/LC_MESSAGES/django.po | 242 ++++++++++++------------ 2 files changed, 120 insertions(+), 122 deletions(-) diff --git a/feincms/locale/de/LC_MESSAGES/django.mo b/feincms/locale/de/LC_MESSAGES/django.mo index 10c5a264e2d3859acfc20565f3c0617ab437b3bf..e189f76159e9abaeed7e0585c6c551afbe6d39c1 100644 GIT binary patch delta 5507 zcmb8yd2p2F0mt!YA%LKekPyO=;2Q}?2nhiK1fvj+a9?tGfG8n(lPqj@!|o;_psp4z z9*ETyQCg+qQLUiWMU;Y41+?C%pyC*%GmN4Rv`!t+%3#00eV<JKu+y2o<1e4*dG~#v z^WAsl$5q>#VxOm{Y%&~2Nj5p&(U<`~W43qIS!2r6jah~hFcY_7Uwjd}<6+FhFR?wI zpJB{cOhvUf9lK!->b^$20PjZbi<yTgq;g_EcEAr&4IRbd*lN$G_ArLAnM`XoW>N2t zU9ilapMs3V%*M&M3@h<5JP$iDi_Vyasq}C9P|#$DU{5T?8k~#$a2Kk<BglW|1b=AD zoWp^b!A+Xc#h8Xuu@hd2=i@RQgaOn5?nO=HLF_>P=1~e7(H}92J23_GnVuRdLe)oO ze=I|-)U~J%T<n9Zumm^YD0~IAvS&~O?$pcMifmN90Asx=lvB_Q79*=|YEdh)79Yaf zPy-yy#ky_;mg0ESOjg_TYHT9)4XCAm4>f@vj7~GpMzu2lx8SfotiMM5CMVSK&*)$V zPl`G!K@DUAs-wBcWX$ELhJvV-S&iIku1ESb_v2`M4wvB9sOu_tB6Z&kRDEGK>#vTk z;)FV=!7$dN_Wl@_<IkuY%5%IKRp4amvvC66gSX&e9Eyv%Sr6}eEW+Jbg(q+X&brW; zkr<0n$fuA%4WJdZx5rTf`v#}t8N39?JKjvML#@PS)I<3U>RC95TJrZ%?HxsZ{f?nN z|2t}>e?mP2vD94esn0{*ScdvKO+xM29P1UR0WCvqNj>WNwYI*_dN*o`x7yF2wCA5i zt>8Y?Kn{5Im^oxWID(q_r>KUHSx?yW|FHGbr~#fs4Y2b?Uc>3Aj<c+})&f+!qfjeS zX6qA^^_Vf!C}>7=Q4K7$)}lICg_`*q)C|_62C%`p8TrPVZKy5Tjhf;6sP{oDs{K=_ zH|AMXJKgv$_n?21L7_bkMm0PX)$tfq$K|LSX4}u_qh_=eHKQt9UxB)>0kyX+_VbOX zfo!tpA4g4e560BNK?)l22dMhzw*D=ugEOcb&Y=c)UY@r_8K@5Xq6U~}&*!5ay5XpS zmZRF4f+;u~b>I9vzW*B85>9Ao0``I%P&ckab$lCYMsZZbPoM_+0;b>rY=>{4?t2?G z&<{`@x1!oVj^#dMPUAT0V+OMR+OwvC#_-iO8&O}U?KlKqMXk(9%*P*b0QMi`?fG=% zlv##)@vKLE{xI^=G_PYPJccQF0%zb!)IdvPgS`=sLv>Vv8pvg+212M6xD|PcnR~DT zpT;`;9`*TBMyDCqqE<AFdiSqG`Z95>#yzO^9cHJ8Ha3oeLtzmnR|0uSnT@u-12waQ z*b%=#b?_w?;Ti0N0}H&*i%>Hgg`Kes*I@;A!8cIXANJ}o^BDy#*;l9~>N?ch<8;(O za#8Q{a=a9qQ8RlU^-LT@JrkdzCh#@Vl<^gMdtQjz(($N)FTy9V2D|C^Kb2`*z=?i1 z6AQ2_HlsSY1?S-woQ2=wd00Bka{_9nGw>-~h}t4k?7ga|pni@k@qFBjY4`|s*7tuW z1^p<zj9P*3P)l?g^$eUt%^-_klxbLq6R-)jB`;zs?n4diJ?xI3pg#Ww{rDYf&zI2I z#TdqzI^01)7e0p*aW`tFXEBb``Ki(jT2Wh&QR4mnUxq>Ix1$F1BbH+s7gIFXp`L|j ztuLUSrI&C#emsixFQt&h2J>z)^H5KD6!m-l8`MMd6l!L>Pz~-w&G;Z{Nsn0nhT6K5 zsQZ6Htz^$JUOW9zTa|C?Bgbg}IWdkCX*dV964#=hi5hDJb>oewf!vPjIF1_7R@C*6 zVR9u=1K(}y2T=FFWj%r#*cUN-!B?n}pRymEMKzql^617cs1ACd29S$tU<j(i5vZ*k zYwP1s*Hzg198`OYQ1>mtOpH}g(2XsqmAC;lvyIpbx1g3Xfg0eusE6w_TR&wzi)yFK zSnq3?itVWnLS0{gT9Hdp{{u1&8BokzO+g(lN6jRN>ZlPlgLT#o*pvDu)IhhR8ro|; zWX~VRbk2W|>aY`!y4p`i-PaGbqD7dZ?|&%;EzPB<rI}<en3=qQC9~%jqn?rFwjMzZ zaIN)b>z&s7P#tYWt<00Cex61RY$x{A_kSM+HT)5F!>>?FcN%r$zfd>+jJmNynYU7D z*n@f&@}rh~jqB^H;~i2%rVw_<xMT<Ui2R<k9kE7AFOqkO2GKxtY$wG;Gti(W5xtJD zBs%t!K(fR?T<{Rdvh^+KCohv_M8_2*Oa>8c?<0gGmfRbaChHG}9+tn7&4jP7xslvV z?j<_jBYN3fs0znwqE$?&!f}&_c^lV|LR(*m&EyVSpN+N2J1LZt-;!I1j-4LKfBigY z%VY3bTh6t%!JG9Lhu)NJN0dT~tvrg;$?YV${|{5pliYT^L}3+~N-nY|7g&2^CD}{( zH;H+c=)G_!`2*2WK>89rGp`dJGsyd7A9<cECo4(pN&e{gl}GaLUHpB<)~l^Nd*;vN z*JK#kNb1RM(ss<Fz_V!DkzV$sz9Ds_ggim!liP@nBi_z=Upu{xW+qR2KPm?(zd}B+ z=lD7&k4^l&noJ}8$=yW967mUoS{05wvX)$?3dc}#l>CW2PKrpf|2fHm_e(dDa)qtG zX}ul~l6*3r^dK*g6w-G5&K6$7%gKjifIat=^?uZgX%ty+&yCQNyMa7LE+O}jzmRd{ zRkDlBC5y;?L`Q@?mn`wR#wxOoq>>z>qYqh1-XKFrd!l0->6k1Ta}8Dw<j-5=V{#Q4 zOcoOzA<`vT;-?sA*>W3)DeNIl_QV5tE7?k}v*%XCbJE{U{E)uAT~4T>#i<Gfqi!(j z)PzIzPPEQ-LScWcKUf)vZ_6yma3fV=e?!zC3Ob=0$6sGr>n7gHyuN)b5=mYhscdqc z<&DuO7c6%Jp=Ku<a>8y^sL2g;fj{C<h}hectuJ5URz-`<ys-Pfo8Z2v8vE~!bV#-m zpWJ&zd`Iu$@l%C;;%9pAN$l=(jW6EX_k!-#ZorMY)y{y3<Bz)ak)n8BcK;mamK=3M zn3;rIoRw~ird8=QXkJsZo7xT5kefq|foi8J>{doyJ`99H4URvUytB^lhAYEWbuEcK z{W|!%2BK~_sH>vx>S+As3uiyl-SKs-35Dw`qw%!dsfnv|@9-r~UR2`iI<l~MMB(t! zPI2+Y#l?xDya#-Vj|YrwpEEsJR~d*pD?{}SwCx6+CYEw;+a7ezADcCiO{fdI{^gCq zTBq8LI1~K=NKD8-<m=$CuXn?V%!1N(vB`cn;yRbx^<G&S3_8_~jMbSO-oLkMB~9z* z1r4shs*Yh7&J2bcYB<yEcdOknr)u3u)D1A0W;a~z2F?H1VD^7nT+^8BvDU2%+13&> z3g7W1a)w>yD`HD30&YFeoa@xOf&IIf9S_7}zZ)oAG=G*8Vld7Emu(9cPOnbfRs7F( zB^rs-ynipla$JAVbrw|B1zdlPt9{Y+)9k+Z`8>SFZLD>JiJL}d`cfCNF|2QLoBT~~ j{Na*b@f{^Y60IfKzK&D8jrw6!MPkzE*L?A`(y#vwym{N$ delta 4949 zcmYk<2~<?q0mkt=ASxnmh%9ac3L*g!L_~}RiTjeojYO%5fFn>56_JSB7*m(T-HFyM zw$*5CG*&al*u<*QR^t-mPLHjoG4^QFcoM5UjXlQp|INFclXv*$cki3`?)Da7PxYhe z-kUAztut)3qz$=J-<SlKG0VfX*BEyTV<uo6M&d$jjT^8z9>9)x5*y<`F&KZqp7<Em zZdQabO>h+I{37IdubEFl4J^Z^xDP|{7^<O@n2u-c{>R7|O;Ah6P>iD93>#sR-QNxA z+vH$B9FB#!78~M245febBL#Kbfaz({QP>I-a1uU^YG^z1V-E6>i04o<et^wTCpCcP z7=|&}2@_Bq4o3|<A2q@87)t-9m_ij!!FqTL)zBSV{|-A)e~3CUn(3;8b{LDvn2G(d zJI=<yN+NSJ$52au)z)ug4E0Co)eIt{3A#}$kcnF{4@2=Q3|w2xrv3wJCh4@I{n@Ai z_s76YQRn632AqHz;3HH&T^O|+^I}<lHBihBbvzB#@O)%&W)Z5Pw^1weuKj)w@?-pb z(55+$S$G!<uswH}j-P`%e}S#PiRy0^s-G>bS^r83+u5NdYQ?RprA|OKFc>wn=dd5< zV_)2ii|_`fU~yaLCS8qPs2|5-ypI_;rkyd}a4D+e!>CJn!b?FTI*kMI8a|Ef+B-8W zK&?bIa-W%%sB8ZYYGC_N4IZ-lkD`|NEb7{SiQG2kA*#bLw{u=|)YIaPp`dHl(VB`H zP!{TvJd5gRgsqRYmY|k)ChB`H>i8w7m0O1z=q6j=Y2A$)$UfveuQ})x%n|#=Nn1aM z8sQbx0KY^vd>7U6J?nq0t~fhGYjf1fM4<-O4s~9NH47W+`Ol@G84pHvkZ&zO4Pb(G zGHNNSQI})|YKA*d&;Nc@N5@fb#tW$SZlNy49n=f$F{)h?&j9G(gi+7{TB1&fLmiNa zTB>x^OnTUQAJmHULp40yeqV$dNSWO~8#UuqsP;Fa2E5bOKR~Z`9HpQR&Z17Zgc`tK zQ3JSxy2kfV9se6O&?k0(FprF$o-ow$v8eXksN*`J&PzcJusdpn26SNkb-+vP(23(w z11Lt#YznI3g{T><K^?ypgK#_Qyq%~4??H9^5vqeDnCs$FU?1wu6P!!;0`g><(gfCD zkJVy!B;yv;tMe3UWoofAevSN?@I>bx=!X25A$;fsG#&N*GUVlG_M=wp3~Ioaa0u37 z2*!7E2AbrhppMc|BkF}}U@U4SDv@`SnT!2#1D4`V`~AQqXXYbNOZzj_1g0Q|n0Yu6 zcc5<GM$E>IamcI2c=IUeZZ1U4qz3Dw57po%)EjL#Ho)ul`&+1)`~ySrJA54<p)SQd zmQ%+sMb%fMR%kP7MLtC?t=F8Sppjff{q}l@y)pSIXC|endtnypURZ$|@D}999N<IO z`fsR9`7hMK8>Seu3u92{9Y@_m7jY=w#Be?T$*E2U+1QXThFkMdGkXPhV;SlaM6w+E z<x_wfa5aYE9#qGNQ0JXSz56etW?VnbS&=Z*%0*zbp8psM8hHi|!a>*<*Pt%NWo(Mq zQ3L!2HRA`U??bvWIBbj>KsB-mW(lfeKkB$cn1@Gk7zU-Y{yqxNQ_xJlMlF2|!_LMR zu>x142J}D7#lHM1(+n0`m!j^SmG}(qLY;pXdGbtLrgIbbN3C2THp01?tiNWogdJ*d zHEJo>Teo32^}VPQ52KE&McrICP!0VZwdCL1`hQU?7Q(EWVI*n=5>fX+sx_xO>#q|B zvO@zIff~R#R7aESf#s+MYET_6u=QoA^VeFppa!<ne!mwrfe-Ee6R392qRzYMrJxc0 z1vP-Xs0Qw%uH7S4$4~6{Az4nn396w;)bXt`5<A%aJyGXBgIbAxsELh6y<aAvR@7TV zK_h$%byID#^#j)9sD>_}9=od;jQ3E--$$)Ta1ZAXk0z*r#iKe*LQNnO)lV<fL<c*1 z%}5HZ*inEQX(dMBLhE|F|2=HM{*O@|evazk&-VM<s3m=f8t@a;K!UjwHGojmN;N|r z7mfAw{KwlbI-zcsG+WO_jdYN8gms*?7}ZcYs>5njhjUN^d<`|R<*0VIV-q}pTEP=o zPtX4;3Oex|>cmT^5#PX;cpLd8X5xq*Lv3ftMADxy(ZC;@@8K1)h16}86h0(di7wY* zqV2bY*N5?{LoK^r3|gLiqU}@ibMhv6mz*cjq;4yr@CotT9b<4RNhF%(uZcF@+}fUX z2wcKZl;0xU(_S-=!fRv=(e^pXC2pc^CYek2slqnjA@EtvXNs+lz$&to93w-BhiKDF z>6c`oDs1~5%qCs`jkc17<H;+ei``d8*Sf+_)Su~f+jI)=*vfBk09it!$lFAhv2OdA zLIv@WcwK*O?HvNo<Qd8@khWwm(PJ~4oFm$jNgJYj=1)Z1KnHUezaSGx8QDp+)%BzD z%VduVY~CV1mXn_3Bl0>qNtO|92OR>R!}-i1K}7F+ZF&MGk#1xMd7dmL+Acc;o}yNi z2if{$JWh^iTo>$4ZgTT`vX+dq`#RuCTONzo$ZlH~uaf6%{VA*^@00B$m1rC4U{)i) zzXJcpY1e1^(7M#X36ezmkVtZX=$W2Ev~6%Of5g$`BI#)N?Xs@J2$D&DVfUru8)O^l zMOKkNkly4d30#+9I8qh6O~c>W@*FHA3rI84j%d^0gazaj=}dx&wqKF@ff9cUVgfl$ zu96o?C-M@}R!;hc1&aJxg&){*9hWE^A~Woc^|**^CbR6mQeW>D=Nl(gOm!C*POB=L zTG83xDB}Gf-?hlj{+6xg1pA_5C;9fLwf1d{jr3hli}8IH`-y*UYmY0uW=eTk#bnP! z_q4(ikMBvF4*ouEtAqSE+XuUR-@Au~6qQdcp6t(wbGdwZ@dJWAldAlS<5##sD$7br ztNblGc6WuRr>1A5X7q5U_sHp*=^vf2(bY6*sHd#L;~wTI@l;IoboPInm>KNrlbr2e znf!&Tp6AuF5`R%jc91_i?TpLi@&DNMWminTr?O}!M|0jNPg#}6j4Sh$r;Zsp%>PEl zgCPI@?k!!uud<?i-)1F;<ON0**`uw?*E74HYleST_E}f`k)Gnxsu{k#oNxXQ2MY{) diff --git a/feincms/locale/de/LC_MESSAGES/django.po b/feincms/locale/de/LC_MESSAGES/django.po index 450967107..12d8cd5b8 100644 --- a/feincms/locale/de/LC_MESSAGES/django.po +++ b/feincms/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" +"POT-Creation-Date: 2013-02-16 00:00+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,16 +17,16 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: models.py:420 content/template/models.py:59 +#: models.py:369 content/template/models.py:59 msgid "template" msgstr "Template" -#: models.py:551 +#: models.py:509 msgid "ordering" msgstr "Sortierung" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "Sprache" @@ -34,7 +34,7 @@ msgstr "Sprache" msgid "All" msgstr "Alle" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Übergeordnet" @@ -43,50 +43,49 @@ msgstr "Übergeordnet" msgid "Category" msgstr "Kategorie" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "%s ändern" #: admin/tree_editor.py:229 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "Titel" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:402 #, python-format msgid "%s has been moved to a new position." msgstr "%s wurde an eine neue Position verschoben." -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:406 msgid "Did not understand moving instruction." msgstr "Unbekannter Verschiebe-Befehl." -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:415 msgid "actions" msgstr "Aktionen" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:427 msgid "Successfully deleted %s items." -msgstr "Element wirklich löschen?" +msgstr "%s Elemente gelöscht." -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:435 #, fuzzy, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "Gelöschtes Element %(verbose_name)s wiederherstellen" +msgstr "%(verbose_name)s löschen" -#: content/application/models.py:272 +#: content/application/models.py:217 msgid "application content" msgstr "Applikation" -#: content/application/models.py:273 +#: content/application/models.py:218 msgid "application contents" msgstr "Applikationen" -#: content/application/models.py:298 +#: content/application/models.py:248 msgid "application" msgstr "Applikation" @@ -143,65 +142,45 @@ msgstr "Datei" msgid "files" msgstr "Dateien" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "Bild" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "Textalternative" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "Beschreibung des Bildes" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "Legende" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "Bilder" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "Position" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "Format" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(Keine Legende)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "Mediendatei" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "Mediendateien" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "Block" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "Links" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "Rechts" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "Typ" @@ -282,27 +261,27 @@ msgstr "Sektion" msgid "sections" msgstr "Sektionen" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "schlicht" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "Titelzeile" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "Titelzeile und -spalte" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "Tabelle" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "Tabellen" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "Daten" @@ -334,7 +313,7 @@ msgstr "Video" msgid "videos" msgstr "Videos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:119 msgid "Tagging" msgstr "" @@ -367,17 +346,17 @@ msgid "tags" msgstr "Begriffe" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "Übersetzung von" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Dieses Feld für Einträge in der Primärsprache leer lassen." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 +#: templates/admin/feincms/item_editor.html:46 msgid "available translations" msgstr "Verfügbare Übersetzungen" @@ -389,35 +368,35 @@ msgstr "Erstellt um" msgid "modification date" msgstr "Verändert um" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:139 msgid "content types" msgstr "Inhaltstypen" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:69 msgid "publication date" msgstr "Veröffentlichen am" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:72 msgid "publication end date" msgstr "Veröffentlicht bis" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:74 msgid "Leave empty if the entry should stay active forever." -msgstr "Leer lassen wenn das Element ewig aktiv bleiben soll." +msgstr "Leer lassen wenn das Element immer aktiv bleiben soll." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:105 msgid "visible from - to" msgstr "sichtbar von – bis" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:115 msgid "Date-based publishing" msgstr "Datumsbasierte Veröffentlichung" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:11 msgid "featured" msgstr "Feature" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:16 msgid "Featured" msgstr "Feature" @@ -437,19 +416,19 @@ msgstr "Meta Beschreibung" msgid "This will be prepended to the default description." msgstr "Diese Beschreibung wird vor der Standard-Beschreibung eingefügt." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Suchmaschinenoptimierung" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:201 msgid "Edit translation" msgstr "Übersetzungen bearbeiten" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:204 msgid "Create translation" msgstr "Übersetzung erstellen" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:209 module/extensions/translations.py:212 msgid "translations" msgstr "Übersetzungen" @@ -473,56 +452,56 @@ msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "%(count)d Mediendatei zu %(category)s hinzugefügt." msgstr[1] "%(count)d Mediendateien zu %(category)s hinzugefügt." -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:76 msgid "Add selected media files to category" msgstr "Ausgewählte zu Kategorie hinzufügen" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:85 #, python-format msgid "ZIP file exported as %s" msgstr "ZIP-Datei exportiert als %s" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:87 #, python-format msgid "ZIP file export failed: %s" msgstr "ZIP-Datei Export fehlgeschlagen: %s" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:92 msgid "Export selected media files as zip file" msgstr "Ausgewählte Mediendateien als ZIP exportieren" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:135 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Vorschau" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:140 module/medialibrary/models.py:88 msgid "file size" msgstr "Dateigrösse" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:145 module/medialibrary/models.py:86 msgid "created" msgstr "Erstellt" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:164 module/medialibrary/models.py:85 msgid "file type" msgstr "Dateityp" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:185 msgid "file info" msgstr "Dateiinfo" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:197 #, python-format msgid "%d files imported" msgstr "%d Dateien importiert" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:199 #, python-format msgid "ZIP import failed: %s" msgstr "ZIP-Import schlug fehl: %s" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:201 msgid "No input file given" msgstr "Keine Datei angegeben" @@ -530,7 +509,7 @@ msgstr "Keine Datei angegeben" msgid "parent" msgstr "Übergeordnet" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "Slug" @@ -594,23 +573,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binärdaten" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "Beschreibung" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "Mediendatei-Übersetzung" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "Mediendatei-Übersetzungen" -#: module/page/forms.py:118 +#: module/page/forms.py:165 msgid "This URL is already taken by an active page." msgstr "Die URL wird schon von einer aktiven Seite verwendet." -#: module/page/forms.py:136 +#: module/page/forms.py:183 msgid "This URL is already taken by another active page." msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." @@ -618,50 +597,55 @@ msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." msgid "Other options" msgstr "Weitere Optionen" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:95 module/page/models.py:174 msgid "in navigation" msgstr "Im Menü" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:110 msgid "Add child page" msgstr "Unterseite hinzufügen" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:112 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Auf der Webseite anzeigen" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:131 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:161 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:175 msgid "You don't have the necessary permissions to edit this object" msgstr "Ungenügende Berechtigung um dieses Objekt zu bearbeiten" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:190 msgid "inherited" msgstr "geerbt" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:194 msgid "extensions" msgstr "Erweiterungen" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:198 module/page/models.py:206 msgid "is active" msgstr "Aktiv" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "Aktiv" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "Überschriebene URL" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -671,23 +655,23 @@ msgstr "" "eine lokale URL handelt. Dieses Feld bestimmt die Navigation und die URLs " "von Unterseiten." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "Weiterleiten zu" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "Ziel-URL für automatische Weiterleitungen." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "Ziel-URL oder Seiten-Id für automatische Weiterleitungen." -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "Zwischengespeicherte URL" -#: module/page/models.py:161 +#: module/page/models.py:393 msgid "page" msgstr "Seite" -#: module/page/models.py:162 +#: module/page/models.py:394 msgid "pages" msgstr "Seiten" @@ -703,18 +687,18 @@ msgstr "Kurze Zusammenfassung des Seiteninhaltes." msgid "Excerpt" msgstr "Auszug" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:83 +#: module/page/extensions/navigation.py:108 msgid "navigation extension" msgstr "Navigations-Erweiterung" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:111 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "Wähle das Modul aus, welches weitere Navigationspunkte erstellt." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "Navigations-Erweiterung" @@ -765,10 +749,6 @@ msgstr "Titel" msgid " By %(filter_title)s " msgstr " Nach %(filter_title)s " -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Suche" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Element wirklich löschen?" @@ -798,7 +778,6 @@ msgid "Really change template? <br />All changes are saved." msgstr "Template wirklich ändern? <br />Alle Änderungen werden gespeichert." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format msgid "" "Really change template? <br />All changes are saved and content from <strong>" "%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." @@ -827,11 +806,15 @@ msgstr "Vorher" msgid "Insert new:" msgstr "Neu einfügen:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "Inhalt kompieren von Original" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Region leer" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." @@ -839,7 +822,7 @@ msgstr "" "Inhalt wird von der übergeordneten Seite geerbt. Füge Inhalt hinzu, um " "dieses Verhalten zu ändern" -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Neues Element hinzufügen" @@ -1002,6 +985,21 @@ msgstr "Senden" msgid "Thanks!" msgstr "Danke!" +#~ msgid "(no caption)" +#~ msgstr "(Keine Legende)" + +#~ msgid "block" +#~ msgstr "Block" + +#~ msgid "left" +#~ msgstr "Links" + +#~ msgid "right" +#~ msgstr "Rechts" + +#~ msgid "Search" +#~ msgstr "Suche" + #~ msgid "Symlinked page" #~ msgstr "Verbundene Seite" From c1a5fd161657e1ccf2aef7bdda037371ab761810 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Sat, 16 Feb 2013 00:39:48 +0100 Subject: [PATCH 0609/1590] Update jquery.alerts.js to 1.01 (minor bug fix) --- feincms/static/feincms/jquery.alerts.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/feincms/static/feincms/jquery.alerts.js b/feincms/static/feincms/jquery.alerts.js index 6d04d510b..a6ec14ed3 100644 --- a/feincms/static/feincms/jquery.alerts.js +++ b/feincms/static/feincms/jquery.alerts.js @@ -1,10 +1,10 @@ // jQuery Alert Dialogs Plugin // -// Version 1.0 +// Version 1.1 // // Cory S.N. LaViska // A Beautiful Site (http://abeautifulsite.net/) -// 29 December 2008 +// 14 May 2009 // // Visit http://abeautifulsite.net/notebook/87 for more information // @@ -17,9 +17,12 @@ // // 1.00 - Released (29 December 2008) // +// 1.01 - Fixed bug where unbinding would destroy all resize events +// // License: // -// This plugin is licensed under the GNU General Public License: http://www.gnu.org/licenses/gpl.html +// This plugin is dual-licensed under the GNU General Public License and the MIT License and +// is copyright 2008 A Beautiful Site, LLC. // (function($) { @@ -176,8 +179,7 @@ width: '100%', height: $(document).height(), background: $.alerts.overlayColor, - opacity: $.alerts.overlayOpacity, - display: 'none' + opacity: $.alerts.overlayOpacity }); break; case 'hide': @@ -206,12 +208,10 @@ if( $.alerts.repositionOnResize ) { switch(status) { case true: - $(window).bind('resize', function() { - $.alerts._reposition(); - }); + $(window).bind('resize', $.alerts._reposition); break; case false: - $(window).unbind('resize'); + $(window).unbind('resize', $.alerts._reposition); break; } } From 3eb03e3c41ed1f0692a0209b7fe0c661a889fe7c Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 22 Feb 2013 16:11:18 +0100 Subject: [PATCH 0610/1590] Remove unused import --- feincms/views/cbv/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/views/cbv/urls.py b/feincms/views/cbv/urls.py index 4387f6f33..91ab4156a 100644 --- a/feincms/views/cbv/urls.py +++ b/feincms/views/cbv/urls.py @@ -1,6 +1,6 @@ from __future__ import absolute_import -from django.conf.urls import patterns, include, url +from django.conf.urls import patterns, url from .views import Handler handler = Handler.as_view() From f48098e98324b1740ecb23c4f3bacc78e80845d9 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 25 Feb 2013 18:02:46 +1100 Subject: [PATCH 0611/1590] Fix #390: No longer depend on return value of add-row handler. --- feincms/static/feincms/item_editor.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 7251769e3..35934d91a 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -182,13 +182,12 @@ if(!Array.indexOf) { for(var i = 0; i < 2; i++){ // Use Django's built-in inline spawing mechanism (Django 1.2+) // must use django.jQuery since the bound function lives there: - var returned = django.jQuery('#'+modvar+'_set-group').find( + django.jQuery('#'+modvar+'_set-group').find( 'div.add-row > a').triggerHandler('click'); - if(returned==false) break; // correct return value - } - var new_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val(), 10); - if(new_form_count > old_form_count){ - return $('#'+modvar+'_set-'+(new_form_count-1)); + var new_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val(), 10); + if(new_form_count > old_form_count){ + return $('#'+modvar+'_set-'+(new_form_count-1)); + } } } From cfd169efa900f8d03ec34367d3140373a6e55eab Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Feb 2013 17:05:46 +0100 Subject: [PATCH 0612/1590] Update the release notes for v1.7 --- docs/releases/1.7.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index f640694e6..146606fd1 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -160,6 +160,17 @@ Notable features and improvements class anymore; hooks are provided to use your own models instead. Please refer to the source for additional information. +* ``Page.redirect_to`` can also contain the primary key of a page now, which + means that the redirect target stays correct even if the page URL changes. + +* Before, page content was copied automatically when creating a translation + of an existing page. This behavior can be deactivated by unchecking a + checkbox now. + +* Work has begun to make the page forms, model admin classes and managers + work with an abstract page model so that it will be easier to work with + several page models in a single Django site. + Bugfixes ======== @@ -180,6 +191,17 @@ Bugfixes * Various ``save`` and ``delete`` methods now come with ``alters_data=True`` to prevent their use in templates. +* Only one translation is permitted per language when using + :py:mod:`feincms.translations`. + +* FeinCMS can now be used without :py:mod:`django.contrib.sites`. + +* If the fieldset of a content inline has been customized, the fieldset is + not processed again to make sure that all form fields are actually shown. + If you use dynamically generated fields in a content inline such as the + application content does, you must not customize the fieldsets attribute + of the ``FeinCMSInline``. + Compatibility with Django and other apps ======================================== From f04ec747ad74054a5b1352488d6127f360627c2a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Feb 2013 17:11:40 +0100 Subject: [PATCH 0613/1590] Move the extensions docs into their own file --- .gitignore | 1 + docs/extensions.rst | 69 +++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + docs/releases/1.7.rst | 64 +-------------------------------------- 4 files changed, 72 insertions(+), 63 deletions(-) create mode 100644 docs/extensions.rst diff --git a/.gitignore b/.gitignore index 0a9c02573..cfd965a3f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ /build /dist tests/test.zip +/docs/_build diff --git a/docs/extensions.rst b/docs/extensions.rst new file mode 100644 index 000000000..b968885fc --- /dev/null +++ b/docs/extensions.rst @@ -0,0 +1,69 @@ +.. _extensions: + +Extensions +========== + +The extensions mechanism has been refactored to remove the need to make models +know about their related model admin classes. The new module +:py:mod:`feincms.extensions` contains mixins and base classes - their purpose +is as follows: + +.. class:: feincms.extensions.ExtensionsMixin + + This mixin provides the ``register_extensions`` method which is the place + where extensions are registered for a certain model. Extensions can be + specified in the following ways: + + - Subclasses of :py:class:`~feincms.extensions.Extension` + - Dotted Python module paths pointing to a subclass of the aforementioned + extension class + - Dotted Python module paths pointing to a module containing either a class + named ``Extension`` or a function named ``register`` (for legacy + extensions) + + +.. class:: feincms.extensions.Extension + + This is the base class for your own extension. It has the following methods + and properties: + + .. attribute:: model + + The model class. + + .. method:: handle_model(self) + + The method which modifies the Django model class. The model class is + available as ``self.model``. + + .. method:: handle_modeladmin(self, modeladmin) + + This method receives the model admin instance bound to the model. This + method could be called more than once, especially when using more than + one admin site. + + +.. class:: feincms.extensions.ExtensionModelAdmin() + + This is a model admin subclass which knows about extensions, and lets the + extensions do their work modifying the model admin instance after it has + been successfully initialized. It has the following methods and properties: + + .. method:: initialize_extensions(self) + + This method is automatically called at the end of initialization and + loops through all registered extensions and calls their + ``handle_modeladmin`` method. + + .. method:: add_extension_options(self, \*f) + + This is a helper to add fields and fieldsets to a model admin instance. + Usage is as follows:: + + modeladmin.add_extension_options('field1', 'field2') + + Or:: + + modeladmin.add_extension_options(_('Fieldset title'), { + 'fields': ('field1', 'field2'), + }) diff --git a/docs/index.rst b/docs/index.rst index 46e071892..e7b5c6bb9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -49,6 +49,7 @@ Contents installation page contenttypes + extensions admin integration medialibrary diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index 146606fd1..a7abf3d31 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -11,69 +11,7 @@ Extensions-mechanism refactor The extensions mechanism has been refactored to remove the need to make models know about their related model admin classes. The new module :py:mod:`feincms.extensions` contains mixins and base classes - their purpose -is as follows: - -**TODO move this somewhere else, this isn't release notes material** - -.. class:: feincms.extensions.ExtensionsMixin - - This mixin provides the ``register_extensions`` method which is the place - where extensions are registered for a certain model. Extensions can be - specified in the following ways: - - - Subclasses of :py:class:`~feincms.extensions.Extension` - - Dotted Python module paths pointing to a subclass of the aforementioned - extension class - - Dotted Python module paths pointing to a module containing either a class - named ``Extension`` or a function named ``register`` (for legacy - extensions) - - -.. class:: feincms.extensions.Extension - - This is the base class for your own extension. It has the following methods - and properties: - - .. attribute:: model - - The model class. - - .. method:: handle_model(self) - - The method which modifies the Django model class. The model class is - available as ``self.model``. - - .. method:: handle_modeladmin(self, modeladmin) - - This method receives the model admin instance bound to the model. This - method could be called more than once, especially when using more than - one admin site. - - -.. class:: feincms.extensions.ExtensionModelAdmin() - - This is a model admin subclass which knows about extensions, and lets the - extensions do their work modifying the model admin instance after it has - been successfully initialized. It has the following methods and properties: - - .. method:: initialize_extensions(self) - - This method is automatically called at the end of initialization and - loops through all registered extensions and calls their - ``handle_modeladmin`` method. - - .. method:: add_extension_options(self, \*f) - - This is a helper to add fields and fieldsets to a model admin instance. - Usage is as follows:: - - modeladmin.add_extension_options('field1', 'field2') - - Or:: - - modeladmin.add_extension_options(_('Fieldset title'), { - 'fields': ('field1', 'field2'), - }) +is as follows: :ref:`extensions`. View code refactor From f5f0419cd1b8b3c4057c4a2947089438181e8e96 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 11:25:34 +0100 Subject: [PATCH 0614/1590] Add a TODO --- feincms/module/page/extensions/navigation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index bb851cc80..4f04fa684 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -99,7 +99,7 @@ def navigation_extension_choices(): class Extension(extensions.Extension): - ident = 'navigation' + ident = 'navigation' # TODO actually use this def handle_model(self): self.model.add_to_class('navigation_extension', From c69483264b71f2024583b7d03022c8603c94dc81 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 16:54:25 +0100 Subject: [PATCH 0615/1590] FeinCMS v1.6.4 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 7fb46bea6..accfbdf73 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 6, 3) +VERSION = (1, 6, 4) __version__ = '.'.join(map(str, VERSION)) From c378af35b95d0702ae78938dad2b576ccf21cff2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 17:28:06 +0100 Subject: [PATCH 0616/1590] Fix #382: Do not crash if video URL could not be parsed --- feincms/content/video/models.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index cbf5ec327..3eab9f909 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -17,13 +17,20 @@ class VideoContent(models.Model): """ PORTALS = ( - ('youtube', re.compile(r'youtube'), lambda url: {'v': re.search(r'([?&]v=|./././)([^#&]+)', url).group(2)}), - ('vimeo', re.compile(r'vimeo'), lambda url: {'id': re.search(r'/(\d+)', url).group(1)}), - ('sf', re.compile(r'sf\.tv'), lambda url: {'id': re.search(r'/([a-z0-9\-]+)', url).group(1)}), + ('youtube', re.compile(r'youtube'), lambda url: { + 'v': re.search(r'([?&]v=|./././)([^#&]+)', url).group(2), + }), + ('vimeo', re.compile(r'vimeo'), lambda url: { + 'id': re.search(r'/(\d+)', url).group(1), + }), + ('sf', re.compile(r'sf\.tv'), lambda url: { + 'id': re.search(r'/([a-z0-9\-]+)', url).group(1), + }), ) video = models.URLField(_('video link'), - help_text=_('This should be a link to a youtube or vimeo video, i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0')) + help_text=_('This should be a link to a youtube or vimeo video,' + ' i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0')) class Meta: abstract = True @@ -31,14 +38,19 @@ class Meta: verbose_name_plural = _('videos') def render(self, **kwargs): - context_instance = kwargs.get('context', None) + context_instance = kwargs.get('context') for portal, match, context_fn in self.PORTALS: if match.search(self.video): + try: + ctx = context_fn(self.video) + except AttributeError: + continue + return render_to_string([ 'content/video/%s.html' % portal, 'content/video/unknown.html', - ], dict(context_fn(self.video), content=self), + ], dict(ctx, content=self), context_instance=context_instance) return render_to_string('content/video/unknown.html', { From f2dcfde8142c0033a053b9cbe2a271b8cd51f674 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 17:40:27 +0100 Subject: [PATCH 0617/1590] FeinCMS v1.7.0 --- docs/releases/1.7.rst | 6 +++--- feincms/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index a7abf3d31..835c053c0 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -1,6 +1,6 @@ -==================================== -FeinCMS 1.7 release notes (upcoming) -==================================== +========================= +FeinCMS 1.7 release notes +========================= Welcome to FeinCMS 1.7! diff --git a/feincms/__init__.py b/feincms/__init__.py index 564317a46..65dbe3019 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 7, 0, 'pre') +VERSION = (1, 7, 0) __version__ = '.'.join(map(str, VERSION)) From 10130ff9bb74d01cf2c05ac3d74b6341bfcbc4d9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 17:52:29 +0100 Subject: [PATCH 0618/1590] Start the v1.8 branch --- README.rst | 6 - docs/index.rst | 1 + docs/installation.rst | 8 +- docs/releases/1.8.rst | 48 +++++ feincms/__init__.py | 2 +- feincms/admin/editor.py | 10 - feincms/content/medialibrary/v2.py | 12 -- feincms/content/richtext/models.py | 26 +-- feincms/content/section/models.py | 22 +-- feincms/extensions.py | 41 +---- feincms/module/mixins.py | 7 - feincms/module/page/models.py | 10 +- .../page/templatetags/feincms_page_tags.py | 51 ------ feincms/utils/html/cleanse.py | 172 ------------------ requirements.txt | 4 +- tests/tox.ini | 9 +- 16 files changed, 73 insertions(+), 356 deletions(-) create mode 100644 docs/releases/1.8.rst delete mode 100644 feincms/admin/editor.py delete mode 100644 feincms/content/medialibrary/v2.py delete mode 100644 feincms/utils/html/cleanse.py diff --git a/README.rst b/README.rst index 75ce0cf94..aa86d8e25 100644 --- a/README.rst +++ b/README.rst @@ -97,12 +97,6 @@ Optional Packages <http://tidy.sourceforge.net>`_ while editing content. Install pytidylib and add ``FEINCMS_TIDY_HTML = True`` to your settings.py. -* Alternately, `lxml <http://pypi.python.org/pypi/lxml>`_ can be installed to perform - silent HTML cleanup to remove non-standard markup while editing content. - Install lxml and add ``cleanse=True`` when you register ``RichTextContent`` - or ``SectionContent``:: - - RichTextContentType = Page.create_content_type(RichTextContent, cleanse=True) Repository branches ------------------- diff --git a/docs/index.rst b/docs/index.rst index e7b5c6bb9..658ff44a9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -92,6 +92,7 @@ Releases .. toctree:: :maxdepth: 1 + releases/1.8 releases/1.7 releases/1.6 releases/1.5 diff --git a/docs/installation.rst b/docs/installation.rst index 21919704c..2103ce2fe 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -23,7 +23,7 @@ which you can download using the Git_ version control system:: $ git clone git://github.com/feincms/feincms.git Feincms, some content types or cleaning modules are dependent on the following apps, which are installed when using pip: -lxml_, feedparser_, PIL_, django-mptt_ and BeautifulSoup_. +feedparser_, Pillow_ and django-mptt_. However, django-tagging_ is not installed because the blog module that uses it is merely a proof of concept. If you are looking to implement a blog, check out elephantblog_. @@ -37,10 +37,8 @@ TinyMCE_ works out of the box and is recommended. .. _Subversion: http://subversion.tigris.org/ .. _django-mptt: http://github.com/django-mptt/django-mptt/ .. _django-tagging: http://code.google.com/p/django-tagging/ -.. _lxml: http://codespeak.net/lxml/ .. _feedparser: http://www.feedparser.org/ -.. _PIL: http://www.pythonware.com/products/pil/ -.. _BeautifulSoup: http://pypi.python.org/pypi/BeautifulSoup/3.2.1 +.. _Pillow: https://pypi.python.org/pypi/Pillow/ .. _elephantblog: http://github.com/feincms/feincms-elephantblog .. _TinyMCE: http://www.tinymce.com/ .. _CKEditor: http://ckeditor.com/ @@ -69,4 +67,4 @@ pages and this is the most advanced module of FeinCMS too. Please proceed to :ref:`page` to find out how you can get the page module up and running. -.. _settings: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#how-django-discovers-language-preference \ No newline at end of file +.. _settings: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#how-django-discovers-language-preference diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst new file mode 100644 index 000000000..0eb78ff4b --- /dev/null +++ b/docs/releases/1.8.rst @@ -0,0 +1,48 @@ +==================================== +FeinCMS 1.8 release notes (upcoming) +==================================== + +Welcome to FeinCMS 1.8! + + +Major feature 1 +=============== + + +Backwards-incompatible changes +============================== + + +Removal of deprecated features +------------------------------ + +* The old media library content type module + :py:mod:`feincms.content.medialibrary.models` has been replaced with the + contents of :py:mod:`feincms.content.medialibrary.v2`. The model field + ``position`` has been renamed to ``type``, instead of ``POSITION_CHOICES`` + you should use ``TYPE_CHOICES`` now. The code has been simplified and + hacks to imitate ``raw_id_fields`` have been replaced by working stock + code. The ``v2`` module will stay around for another release and will be + removed in FeinCMS v1.8. The now-unused template + ``admin/content/mediafile/init.html`` has been deleted. + + +New deprecations +---------------- + +* ``Page.setup_request()`` does not do anything anymore and will be removed + in FeinCMS v1.8. + + +Notable features and improvements +================================= + + +Bugfixes +======== + + +Compatibility with Django and other apps +======================================== + +FeinCMS 1.8 requires Django 1.4 (or even Django 1.5?). diff --git a/feincms/__init__.py b/feincms/__init__.py index 65dbe3019..45db6bd53 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 7, 0) +VERSION = (1, 8, 0, 'pre') __version__ = '.'.join(map(str, VERSION)) diff --git a/feincms/admin/editor.py b/feincms/admin/editor.py deleted file mode 100644 index c991ee1f3..000000000 --- a/feincms/admin/editor.py +++ /dev/null @@ -1,10 +0,0 @@ -import warnings -warnings.warn("Accessing the item and tree editor through `feincms.admin.editor`" - " has been deprecated. Please use `feincms.admin.item_editor` and" - " `feincms.admin.tree_editor` instead. `feincms.admin.editor` will be" - " removed in FeinCMS v1.8.", - DeprecationWarning, stacklevel=2) - -from feincms.admin.item_editor import ItemEditor, ItemEditorForm -from feincms.admin.tree_editor import TreeEditor, ajax_editable_boolean, \ - ajax_editable_boolean_cell, django_boolean_icon diff --git a/feincms/content/medialibrary/v2.py b/feincms/content/medialibrary/v2.py deleted file mode 100644 index 5dd30df2e..000000000 --- a/feincms/content/medialibrary/v2.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import absolute_import -import warnings - - -warnings.warn( - 'The contents of feincms.content.medialibrary.v2 have been moved to' - ' feincms.content.medialibrary.models. Support for importing those' - ' classes through v2 will be removed in FeinCMS v1.8.', - DeprecationWarning, stacklevel=2) - - -from .models import * diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index f15c580ce..a0a340d97 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -64,8 +64,8 @@ class RichTextContent(models.Model): anything you want using ``FEINCMS_RICHTEXT_INIT_CONTEXT`` and ``FEINCMS_RICHTEXT_INIT_TEMPLATE``. - Optionally runs the HTML code through HTML cleaners if you specify - ``cleanse=True`` when calling ``create_content_type``. + Optionally runs the HTML code through HTML cleaners if you pass a callable + as ``cleanse`` when calling ``create_content_type``. """ form = RichTextContentAdminForm @@ -91,7 +91,7 @@ def render(self, **kwargs): def save(self, *args, **kwargs): # TODO: Move this to the form? - if getattr(self, 'cleanse', False): + if getattr(self, 'cleanse', None): # Passes the rich text content as first argument because # the passed callable has been converted into a bound method self.text = self.cleanse(self.text) @@ -100,30 +100,14 @@ def save(self, *args, **kwargs): save.alters_data = True @classmethod - def initialize_type(cls, cleanse=False): + def initialize_type(cls, cleanse=None): def to_instance_method(func): def func_im(self, *args, **kwargs): return func(*args, **kwargs) return func_im if cleanse: - # If cleanse is True use default cleanse method - if cleanse == True: - import warnings - warnings.warn("Please pass a callable instead. cleanse=True is" - " being deprecated in favor of explicitly specifying the" - " cleansing function. To continue using the same" - " functionality, pip install feincms-cleanse and pass" - " cleanse=feincms_cleanse.cleanse_html to the" - " create_content_type call." - " Support for cleanse=True will be removed in FeinCMS v1.8.", - DeprecationWarning, stacklevel=2) - - from feincms.utils.html.cleanse import cleanse_html - cls.cleanse = to_instance_method(cleanse_html) - # Otherwise use passed callable - else: - cls.cleanse = to_instance_method(cleanse) + cls.cleanse = to_instance_method(cleanse) # TODO: Move this into somewhere more generic: if settings.FEINCMS_TIDY_HTML: diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 0e27b7190..eb8312ada 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -42,7 +42,7 @@ class Meta: verbose_name_plural = _('sections') @classmethod - def initialize_type(cls, TYPE_CHOICES=None, cleanse=False): + def initialize_type(cls, TYPE_CHOICES=None, cleanse=None): if 'feincms.module.medialibrary' not in django_settings.INSTALLED_APPS: raise ImproperlyConfigured, 'You have to add \'feincms.module.medialibrary\' to your INSTALLED_APPS before creating a %s' % cls.__name__ @@ -54,23 +54,7 @@ def initialize_type(cls, TYPE_CHOICES=None, cleanse=False): default=TYPE_CHOICES[0][0])) if cleanse: - # If cleanse is True use default cleanse method - if cleanse == True: - import warnings - warnings.warn("Please pass a callable instead. cleanse=True is" - " being deprecated in favor of explicitly specifying the" - " cleansing function. To continue using the same" - " functionality, pip install feincms-cleanse and pass" - " cleanse=feincms_cleanse.cleanse_html to the" - " create_content_type call." - " Support for cleanse=True will be removed in FeinCMS v1.8.", - DeprecationWarning, stacklevel=2) - - from feincms.utils.html.cleanse import cleanse_html - cls.cleanse = cleanse_html - # Otherwise use passed callable - else: - cls.cleanse = cleanse + cls.cleanse = cleanse @classmethod def get_queryset(cls, filter_args): @@ -91,7 +75,7 @@ def render(self, **kwargs): ], {'content': self}) def save(self, *args, **kwargs): - if getattr(self, 'cleanse', False): + if getattr(self, 'cleanse', None): try: # Passes the rich text content as first argument because # the passed callable has been converted into a bound method diff --git a/feincms/extensions.py b/feincms/extensions.py index 0af2a5b56..702d14fac 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -37,13 +37,6 @@ def register_extensions(cls, *extensions): cls._extensions = [] cls._extensions_seen = [] - here = cls.__module__.split('.')[:-1] - search_paths = [ - '.'.join(here + ['extensions']), - '.'.join(here[:-1] + ['extensions']), - 'feincms.module.extensions', - ] - for ext in extensions: if ext in cls._extensions: continue @@ -51,33 +44,13 @@ def register_extensions(cls, *extensions): extension = None if isinstance(ext, basestring): - paths = [ext, '%s.register' % ext] + [ - '%s.%s.register' % (path, ext) for path in search_paths] - - for idx, path in enumerate(paths): - try: - extension = get_object(path) - - if idx >= 2: - warnings.warn( - 'Using short names for extensions has been' - ' deprecated and will be removed in' - ' FeinCMS v1.8. Please provide the full' - ' python path to the extension' - ' %s instead (%s).' % ( - ext, - re.sub(r'\.register$', '', path), - ), - DeprecationWarning, stacklevel=2) - - break - except (AttributeError, ImportError, ValueError): - pass - - if not extension: - raise ImproperlyConfigured( - '%s is not a valid extension for %s' % ( - ext, cls.__name__)) + try: + extension = get_object(path) + except (AttributeError, ImportError, ValueError): + if not extension: + raise ImproperlyConfigured( + '%s is not a valid extension for %s' % ( + ext, cls.__name__)) if hasattr(extension, 'Extension'): extension = extension.Extension diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 2def20cc1..379086923 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -19,13 +19,6 @@ class ContentModelMixin(object): #: Collection of response processors response_processors = None - def setup_request(self, request): - import warnings - warnings.warn( - '%s.setup_request does nothing anymore, and will be removed in' - ' FeinCMS v1.8', - DeprecationWarning, stacklevel=2) - @classmethod def register_request_processor(cls, fn, key=None): """ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index a15f06689..4b4d3339d 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -122,8 +122,7 @@ def toplevel_navigation(self): return self.in_navigation().filter(parent__isnull=True) - def for_request(self, request, raise404=False, best_match=False, - setup=False): + def for_request(self, request, raise404=False, best_match=False): """ Return a page for the request @@ -147,13 +146,6 @@ def for_request(self, request, raise404=False, best_match=False, request._feincms_page = self.page_for_path(path, raise404=raise404) - if setup: - import warnings - warnings.warn( - 'Calling for_request with setup=True does nothing anymore.' - ' The parameter will be removed in FeinCMS v1.8.', - DeprecationWarning, stacklevel=2) - return request._feincms_page # ------------------------------------------------------------------------ diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index a8fc36edd..6fe836f38 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -139,57 +139,6 @@ def _navext_filter(iterable): return list(queryset) -# ------------------------------------------------------------------------ -class NavigationNode(SimpleAssignmentNodeWithVarAndArgs): - """ - Return a list of pages to be used for the navigation - - level: 1 = toplevel, 2 = sublevel, 3 = sub-sublevel - depth: 1 = only one level, 2 = subpages too - extended: run navigation extension on returned pages, not only on top-level node - - If you set depth to something else than 1, you might want to look into - the tree_info template tag from the mptt_tags library. - - Example:: - - {% feincms_navigation of feincms_page as sublevel level=2,depth=1 %} - {% for p in sublevel %} - <a href="{{ p.get_absolute_url }}">{{ p.title }}</a> - {% endfor %} - """ - - def what(self, instance, args): - warnings.warn('feincms_navigation and feincms_navigation_extended have' - ' been deprecated and will be removed in FeinCMS v1.8. Start using' - ' the new, shiny and bug-free feincms_nav today!', - DeprecationWarning, stacklevel=3) - - return feincms_nav( - self.render_context, - instance, - level=int(args.get('level', 1)), - depth=int(args.get('depth', 1)), - ) -register.tag('feincms_navigation', - do_simple_assignment_node_with_var_and_args_helper(NavigationNode)) - -# ------------------------------------------------------------------------ -class ExtendedNavigationNode(NavigationNode): - def render(self, context): - self.render_context = context - try: - instance = self.in_var.resolve(context) - except template.VariableDoesNotExist: - context[self.var_name] = [] - return '' - - context[self.var_name] = self.what(instance, _parse_args(self.args, context)) - - return '' -register.tag('feincms_navigation_extended', - do_simple_assignment_node_with_var_and_args_helper(ExtendedNavigationNode)) - # ------------------------------------------------------------------------ class ParentLinkNode(SimpleNodeWithVarAndArgs): """ diff --git a/feincms/utils/html/cleanse.py b/feincms/utils/html/cleanse.py deleted file mode 100644 index 35ce3a7e5..000000000 --- a/feincms/utils/html/cleanse.py +++ /dev/null @@ -1,172 +0,0 @@ -from BeautifulSoup import BeautifulSoup -import lxml.html -import lxml.html.clean -import re -import unicodedata - - -import warnings -warnings.warn("The module feincms.utils.html.cleanse is being deprecated." - " Please use the feincms-cleanse package (installable with pip) instead." - " Improvements will only be made in the feincms-cleanse package. This" - " module will be removed in FeinCMS v1.8.", - DeprecationWarning, stacklevel=2) - - -cleanse_html_allowed = { - 'a': ('href', 'name', 'target', 'title'), - 'h2': (), - 'h3': (), - 'strong': (), - 'em': (), - 'p': (), - 'ul': (), - 'ol': (), - 'li': (), - 'span': (), - 'br': (), - 'sub': (), - 'sup': (), - 'anything': (), - } - -cleanse_html_allowed_empty_tags = ('br',) - -cleanse_html_merge = ('h2', 'h3', 'strong', 'em', 'ul', 'ol', 'sub', 'sup') - - -def cleanse_html(html): - """ - Clean HTML code from ugly copy-pasted CSS and empty elements - - Removes everything not explicitly allowed in ``cleanse_html_allowed``. - - Requires ``lxml`` and ``beautifulsoup``. - """ - - doc = lxml.html.fromstring('<anything>%s</anything>' % html) - try: - ignore = lxml.html.tostring(doc, encoding=unicode) - except UnicodeDecodeError: - # fall back to slower BeautifulSoup if parsing failed - from lxml.html import soupparser - doc = soupparser.fromstring(u'<anything>%s</anything>' % html) - - cleaner = lxml.html.clean.Cleaner( - allow_tags=cleanse_html_allowed.keys() + ['style'], - remove_unknown_tags=False, # preserve surrounding 'anything' tag - style=False, safe_attrs_only=False, # do not strip out style - # attributes; we still need - # the style information to - # convert spans into em/strong - # tags - ) - - cleaner(doc) - - # walk the tree recursively, because we want to be able to remove - # previously emptied elements completely - for element in reversed(list(doc.iterdescendants())): - if element.tag == 'style': - element.drop_tree() - continue - - # convert span elements into em/strong if a matching style rule - # has been found. strong has precedence, strong & em at the same - # time is not supported - elif element.tag == 'span': - style = element.attrib.get('style') - if style: - if 'bold' in style: - element.tag = 'strong' - elif 'italic' in style: - element.tag = 'em' - - if element.tag == 'span': # still span - element.drop_tag() # remove tag, but preserve children and text - continue - - # remove empty tags if they are not <br /> - elif not element.text and element.tag not in \ - cleanse_html_allowed_empty_tags and not \ - len(list(element.iterdescendants())): - element.drop_tag() - continue - - # remove all attributes which are not explicitly allowed - allowed = cleanse_html_allowed.get(element.tag, []) - for key in element.attrib.keys(): - if key not in allowed: - del element.attrib[key] - - # just to be sure, run cleaner again, but this time with even more - # strict settings - cleaner = lxml.html.clean.Cleaner( - allow_tags=cleanse_html_allowed.keys(), - remove_unknown_tags=False, # preserve surrounding 'anything' tag - style=True, safe_attrs_only=True - ) - - cleaner(doc) - - html = lxml.html.tostring(doc, method='xml') - - # remove all sorts of newline characters - html = html.replace('\n', ' ').replace('\r', ' ') - html = html.replace(' ', ' ').replace(' ', ' ') - html = html.replace(' ', ' ').replace(' ', ' ') - - # remove wrapping tag needed by XML parser - html = re.sub(r'</?anything>', '', html) - - # remove elements containing only whitespace or linebreaks - whitespace_re = re.compile(r'<([a-z0-9]+)>(<br\s*/>|\ |\ |\s)*</\1>') - while True: - new = whitespace_re.sub('', html) - if new == html: - break - html = new - - # merge tags - for tag in cleanse_html_merge: - merge_str = u'</%s><%s>' - while True: - new = html.replace(merge_str, u'') - if new == html: - break - html = new - - # fix p-in-p tags - p_in_p_start_re = re.compile(r'<p>(\ |\ |\s)*<p>') - p_in_p_end_re = re.compile('</p>(\ |\ |\s)*</p>') - - for tag in cleanse_html_merge: - merge_start_re = re.compile('<p>(\\ |\\ |\\s)*<%s>(\\ |\\ |\\s)*<p>' % tag) - merge_end_re = re.compile('</p>(\\ |\\ |\\s)*</%s>(\\ |\\ |\\s)*</p>' % tag) - - while True: - new = merge_start_re.sub('<p>', html) - new = merge_end_re.sub('</p>', new) - new = p_in_p_start_re.sub('<p>', new) - new = p_in_p_end_re.sub('</p>', new) - - if new == html: - break - html = new - - # remove list markers with <li> tags before them - html = re.sub(r'<li>(\ |\ |\s)*(-|\*|·)(\ |\ |\s)*', '<li>', html) - - # remove p-in-li tags - html = re.sub(r'<li>(\ |\ |\s)*<p>', '<li>', html) - html = re.sub(r'</p>(\ |\ |\s)*</li>', '</li>', html) - - # add a space before the closing slash in empty tags - html = re.sub(r'<([^/>]+)/>', r'<\1 />', html) - - # nicify entities and normalize unicode - html = unicode(BeautifulSoup(html, convertEntities='xml')) - html = unicodedata.normalize('NFKC', html) - - return html - diff --git a/requirements.txt b/requirements.txt index ba0e73b48..ecbf9c410 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,4 @@ Django>=1.4 django-mptt>=0.4 -PIL +Pillow feedparser>=5.1.2 -lxml -BeautifulSoup>=3.1.2 diff --git a/tests/tox.ini b/tests/tox.ini index 208fb8522..b8708994f 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -15,22 +15,19 @@ setenv = basepython = python2.5 deps = django==1.4 - PIL==1.1.7 + Pillow feedparser - lxml [testenv:py26-1.4.X] basepython = python2.6 deps = django==1.4 - PIL==1.1.7 + Pillow feedparser - lxml [testenv:py27-1.4.X] basepython = python2.7 deps = django==1.4 - PIL==1.1.7 + Pillow feedparser - lxml From a9220411610ce6011e5a5229b9b9054b5b35df43 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 20:12:42 +0100 Subject: [PATCH 0619/1590] Fix the get_object invocation in the ExtensionsMixin --- feincms/extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 702d14fac..5bb991d69 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -45,7 +45,7 @@ def register_extensions(cls, *extensions): if isinstance(ext, basestring): try: - extension = get_object(path) + extension = get_object(ext) except (AttributeError, ImportError, ValueError): if not extension: raise ImproperlyConfigured( From 12c720135f60d88349eed078c17456760a86dc42 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 20:12:56 +0100 Subject: [PATCH 0620/1590] The setup argument to for_request has been removed --- feincms/views/cbv/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 5f23fe129..c7a7984d7 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -18,8 +18,7 @@ def page_model(self): def get_object(self): return self.page_model._default_manager.for_request( - self.request, raise404=True, - best_match=True, setup=False) + self.request, raise404=True, best_match=True) def dispatch(self, request, *args, **kwargs): try: From 7c083ef82e55ec9fdc8878ec095fcd8208acc090 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 20:22:16 +0100 Subject: [PATCH 0621/1590] Convert all tests which still used feincms_navigation to use feincms_nav --- docs/templatetags.rst | 10 ++--- .../page/templatetags/feincms_page_tags.py | 5 +-- feincms/tests/page_tests.py | 44 +++++-------------- 3 files changed, 15 insertions(+), 44 deletions(-) diff --git a/docs/templatetags.rst b/docs/templatetags.rst index f4e6373bf..c659f0892 100644 --- a/docs/templatetags.rst +++ b/docs/templatetags.rst @@ -85,19 +85,15 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: <a href="{{ p.get_absolute_url }}">{{ p.title }}</a> {% endfor %} - This template tag has replaced ``feincms_navigation``, which used - a hand-grown parser and had several bugs which were hard to fix without - a complete rewrite. - .. function:: siblings_along_path_to: This is a filter designed to work in close conjunction with the - ``feincms_navigation`` template tag describe above to build a + ``feincms_nav`` template tag describe above to build a navigation tree following the path to the current page. Example:: - {% feincms_navigation of feincms_page as navitems level=1,depth=3 %} + {% feincms_nav feincms_page level=1 depth=3 as navitems %} {% with navitems|siblings_along_path_to:feincms_page as navtree %} {% recursetree navtree %} * {{ node.short_title }} <br> @@ -197,7 +193,7 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: {% load feincms_page_tags %} - {% feincms_navigation of feincms_page as main level=1 %} + {% feincms_nav feincms_page level=1 as main %} {% for entry in main %} <a {% if entry|is_equal_or_parent_of:feincms_page %}class="mark"{% endif %} href="{{ entry.get_absolute_url }}">{{ entry.title }}</a> diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 6fe836f38..d404e69d6 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -30,10 +30,7 @@ def format_exception(e): @register.assignment_tag(takes_context=True) def feincms_nav(context, feincms_page, level=1, depth=1): """ - New, simplified version of the ``{% feincms_navigation %}`` template tag. - - Generally we don't like abbreviations too much, but the similarity with - the HTML5 <nav> tag was just too tempting. + Saves a list of pages into the given context variable. """ if isinstance(feincms_page, HttpRequest): diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 076dc584c..bf2fc602b 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -688,7 +688,7 @@ def test_17_page_template_tags(self): t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for feincms_page as links excludecurrent=1 %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), 'en:/test-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '') # XXX should the other template tags not respect the in_navigation setting too? @@ -698,16 +698,16 @@ def test_17_page_template_tags(self): self.assertEqual(t.render(context), '/test-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '/test-page/test-child-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of request as nav level=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav request level=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') from django.http import HttpRequest request = HttpRequest() request.path = '/test-page/' self.assertEqual(t.render(template.Context({'request': request})), '/test-page/test-child-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=99 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=99 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '') t = template.Template('{% load feincms_page_tags %}{% feincms_breadcrumbs feincms_page %}') @@ -716,16 +716,16 @@ def test_17_page_template_tags(self): self.assertTrue('href="/test-page/">Test page</a>' in rendered, msg="The parent page should be a breadcrumb link") self.assertTrue('href="/test-page/test-child-page/"' not in rendered, msg="The current page should not be a link in the breadcrumbs") - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=2 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '/test-page/test-child-page/,/test-page/test-child-page/page3/') - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=3 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=3 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/,/test-page/test-child-page/page3/') - t = template.Template('{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=3,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=3 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '/test-page/test-child-page/page3/') t = template.Template('{% load feincms_page_tags %}{% if feincms_page|is_parent_of:page3 %}yes{% endif %}|{% if page3|is_parent_of:feincms_page %}yes{% endif %}') @@ -737,9 +737,9 @@ def test_17_page_template_tags(self): t = template.Template('{% load feincms_page_tags %}{% feincms_translatedpage for feincms_page as t1 language=de %}{% feincms_translatedpage for feincms_page as t2 %}{{ t1.id }}|{{ t2.id }}') self.assertEqual(t.render(context), '2|1') - def test_17_feincms_navigation(self): + def test_17_feincms_nav(self): """ - Test feincms_navigation some more + Test feincms_nav some more """ self.login() @@ -794,28 +794,6 @@ def test_17_feincms_navigation(self): Page.objects.filter(id__in=(5, 9, 19)).update(in_navigation=False) tests = [ - ( - {'feincms_page': Page.objects.get(pk=1)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', - ), - ( - {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-332/', - ), - ( - {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=2,depth=3 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-331/page-3311/,/page-3/page-33/page-332/', - ), - ( - {'feincms_page': Page.objects.get(pk=19)}, - '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=2 %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', - ), - - # Exactly the same tests, but with feincms_nav instead of feincms_navigation ( {'feincms_page': Page.objects.get(pk=1)}, '{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', @@ -863,7 +841,7 @@ def test_17_feincms_navigation(self): # Now check that disabling a page also disables it in Navigation: p = Page.objects.get(pk=15) - tmpl = '{% load feincms_page_tags %}{% feincms_navigation of feincms_page as nav level=1,depth=3 %}{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %}' + tmpl = '{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=3 as nav %}{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %}' data = template.Template(tmpl).render(template.Context({'feincms_page': p})), self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") From 8a2f2984ba7f2c355c97ac0d661372b3a863af14 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 20:25:27 +0100 Subject: [PATCH 0622/1590] Remove the cleanse tests because the cleanse module has been removed --- feincms/tests/tests.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/feincms/tests/tests.py b/feincms/tests/tests.py index a6a81a423..fd9d86ba1 100644 --- a/feincms/tests/tests.py +++ b/feincms/tests/tests.py @@ -158,20 +158,3 @@ def test_03_admin(self): self.create_entries() self.assertEqual(self.client.get('/admin/blog/entry/').status_code, 200) self.assertEqual(self.client.get('/admin/blog/entry/1/').status_code, 200) - - -class CleanseTestCase(TestCase): - def test_01_cleanse(self): - from feincms.utils.html.cleanse import cleanse_html - - entries = [ - (u'<p> </p>', u''), - (u'<span style="font-weight: bold;">Something</span><p></p>', u'<strong>Something</strong>'), - (u'<p>abc <span>def <em>ghi</em> jkl</span> mno</p>', u'<p>abc def <em>ghi</em> jkl mno</p>'), - (u'<span style="font-style: italic;">Something</span><p></p>', u'<em>Something</em>'), - (u'<p>abc<br />def</p>', u'<p>abc<br />def</p>'), - (u'<p><p><p> </p> </p><p><br /></p></p>', u' '), - ] - - for a, b in entries: - self.assertEqual(cleanse_html(a), b) From 496e19bd9e081231a3b8c3cd9512582c4f0e564d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 20:26:34 +0100 Subject: [PATCH 0623/1590] Generate HTML coverage after running the testsuite --- tests/cov.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cov.sh b/tests/cov.sh index 9b2e48e63..be468fc5c 100755 --- a/tests/cov.sh +++ b/tests/cov.sh @@ -1,2 +1,3 @@ #!/bin/sh coverage run --branch --include="*feincms*" ./manage.py test feincms +coverage html From 324699b8f169c1be63c408f2248ac99defa5e354 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 21:00:28 +0100 Subject: [PATCH 0624/1590] Remove all references to function-based generic views --- docs/api/views.rst | 28 -------------------------- docs/integration.rst | 4 +--- feincms/views/decorators.py | 23 --------------------- feincms/views/generic/__init__.py | 0 feincms/views/generic/create_update.py | 7 ------- feincms/views/generic/date_based.py | 11 ---------- feincms/views/generic/list_detail.py | 6 ------ feincms/views/generic/simple.py | 5 ----- 8 files changed, 1 insertion(+), 83 deletions(-) delete mode 100644 feincms/views/generic/__init__.py delete mode 100644 feincms/views/generic/create_update.py delete mode 100644 feincms/views/generic/date_based.py delete mode 100644 feincms/views/generic/list_detail.py delete mode 100644 feincms/views/generic/simple.py diff --git a/docs/api/views.rst b/docs/api/views.rst index 0f2d14a2f..c18773bf7 100644 --- a/docs/api/views.rst +++ b/docs/api/views.rst @@ -6,34 +6,6 @@ Views and decorators :noindex: -Generic-views replacements --------------------------- - -All views in the ``feincms.views.generic`` module are almost the same -as their counterparts in ``django.views.generic`` (before class-based -views came along), except that they add a ``feincms_page`` object to -the context. Not recommended anymore because they are deprecated in -Django. Use the ``feincms.context_processors.add_page_if_missing`` -context processor instead. - - -.. automodule:: feincms.views.generic.simple - :members: - :noindex: - -.. automodule:: feincms.views.generic.list_detail - :members: - :noindex: - -.. automodule:: feincms.views.generic.date_based - :members: - :noindex: - -.. automodule:: feincms.views.generic.create_update - :members: - :noindex: - - Decorators ---------- diff --git a/docs/integration.rst b/docs/integration.rst index 73965ea9a..96ab32bb3 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -5,9 +5,7 @@ Integrating 3rd party apps into your site ========================================= With FeinCMS come a set of standard views which you might want to check -out before starting to write your own. Included is a standard view for -pages, and a set of generic view drop-in replacements which know about -the CMS. +out before starting to write your own. Default page handler diff --git a/feincms/views/decorators.py b/feincms/views/decorators.py index 8413d1c90..65bf54acf 100644 --- a/feincms/views/decorators.py +++ b/feincms/views/decorators.py @@ -7,29 +7,6 @@ from feincms.module.page.models import Page -def add_page_to_extra_context(view_func): - """ - Adds the best-match page to the extra_context keyword argument. Mainly used - to provide generic views which integrate into the page module. - """ - - def inner(request, *args, **kwargs): - import warnings - warnings.warn("The `add_page_to_extra_context` view decorator has been" - " deprecated, as have the function-based generic views in" - " `django.views.generic` and `feincms.views.generic`. Use the" - " `feincms.context_processors.add_page_if_missing` context processor" - " and Django's class-based generic views instead.", - DeprecationWarning, stacklevel=2) - - kwargs.setdefault('extra_context', {}) - kwargs['extra_context']['feincms_page'] = Page.objects.for_request( - request, best_match=True) - - return view_func(request, *args, **kwargs) - return wraps(view_func)(inner) - - def standalone(view_func): """ Marks the view method as standalone view; this means that diff --git a/feincms/views/generic/__init__.py b/feincms/views/generic/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/feincms/views/generic/create_update.py b/feincms/views/generic/create_update.py deleted file mode 100644 index be8d7ccf9..000000000 --- a/feincms/views/generic/create_update.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.views.generic import create_update -from feincms.views.decorators import add_page_to_extra_context - - -create_object = add_page_to_extra_context(create_update.create_object) -update_object = add_page_to_extra_context(create_update.update_object) -delete_object = add_page_to_extra_context(create_update.delete_object) diff --git a/feincms/views/generic/date_based.py b/feincms/views/generic/date_based.py deleted file mode 100644 index a4b9df290..000000000 --- a/feincms/views/generic/date_based.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.views.generic import date_based -from feincms.views.decorators import add_page_to_extra_context - - -archive_index = add_page_to_extra_context(date_based.archive_index) -archive_year = add_page_to_extra_context(date_based.archive_year) -archive_month = add_page_to_extra_context(date_based.archive_month) -archive_week = add_page_to_extra_context(date_based.archive_week) -archive_day = add_page_to_extra_context(date_based.archive_day) -archive_today = add_page_to_extra_context(date_based.archive_today) -object_detail = add_page_to_extra_context(date_based.object_detail) diff --git a/feincms/views/generic/list_detail.py b/feincms/views/generic/list_detail.py deleted file mode 100644 index c570d6c84..000000000 --- a/feincms/views/generic/list_detail.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.views.generic import list_detail -from feincms.views.decorators import add_page_to_extra_context - - -object_list = add_page_to_extra_context(list_detail.object_list) -object_detail = add_page_to_extra_context(list_detail.object_detail) diff --git a/feincms/views/generic/simple.py b/feincms/views/generic/simple.py deleted file mode 100644 index 71efcca1c..000000000 --- a/feincms/views/generic/simple.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.views.generic import simple -from feincms.views.decorators import add_page_to_extra_context - - -direct_to_template = add_page_to_extra_context(simple.direct_to_template) From f4abcae38bb5d6962b6b7ddd17894b334b0c65c7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 27 Feb 2013 08:46:41 +0100 Subject: [PATCH 0625/1590] Fix TreeEditor.indented_short_title if get_absolute_url crashes --- feincms/admin/tree_editor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 8322adf26..b68ce66ab 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -209,9 +209,14 @@ def indented_short_title(self, item): """ mptt_opts = item._mptt_meta r = '' - if hasattr(item, 'get_absolute_url'): + try: + url = item.get_absolute_url() + except (AttributeError,): + url = None + + if url: r = '<input type="hidden" class="medialibrary_file_path" value="%s" id="_refkey_%d" />' % ( - item.get_absolute_url(), + url, item.pk ) From 20defaac5c54d7049287456bb7fe914cab082590 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Feb 2013 21:08:58 +0100 Subject: [PATCH 0626/1590] Remove a few unused and ugly template tag helpers --- feincms/utils/templatetags.py | 74 ----------------------------------- 1 file changed, 74 deletions(-) diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index d9c4af9cf..4b8d1c841 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -62,80 +62,6 @@ def render(self, context): return self.what(instance, _parse_args(self.args, context)) -def do_simple_node_with_var_helper(cls): - def _func(parser, token): - try: - tag_name, of_, in_var_name = token.contents.split() - except ValueError: - raise template.TemplateSyntaxError, 'Invalid syntax for %s node: %s' % (cls.__name__, token.contents) - - return cls(tag_name, in_var_name) - - return _func - -class SimpleNodeWithVar(template.Node): - def __init__(self, tag_name, in_var_name): - self.tag_name = tag_name - self.in_var = template.Variable(in_var_name) - - def render(self, context): - self.render_context = context - try: - instance = self.in_var.resolve(context) - except template.VariableDoesNotExist: - return '' - - return self.what(instance) - -def do_simple_assignment_node_helper(cls): - def _func(parser, token): - try: - tag_name, as_, var_name = token.contents.split() - except ValueError: - raise template.TemplateSyntaxError, 'Invalid syntax for %s node: %s' % (cls.__name__, token.contents) - - return cls(tag_name, var_name) - - return _func - -class SimpleAssignmentNode(template.Node): - def __init__(self, tag_name, var_name): - self.tag_name = tag_name - self.var_name = var_name - - def render(self, context): - self.render_context = context - context[self.var_name] = self.what() - return '' - -def do_simple_assignment_node_with_var_helper(cls): - def _func(parser, token): - try: - tag_name, of_, in_var_name, as_, var_name = token.contents.split() - except ValueError: - raise template.TemplateSyntaxError, 'Invalid syntax for %s node: %s' % (cls.__name__, token.contents) - - return cls(tag_name, in_var_name, var_name) - - return _func - -class SimpleAssignmentNodeWithVar(template.Node): - def __init__(self, tag_name, in_var_name, var_name): - self.tag_name = tag_name - self.in_var = template.Variable(in_var_name) - self.var_name = var_name - - def render(self, context): - self.render_context = context - try: - instance = self.in_var.resolve(context) - except template.VariableDoesNotExist: - context[self.var_name] = [] - return '' - - context[self.var_name] = self.what(instance) - return '' - def do_simple_assignment_node_with_var_and_args_helper(cls): def _func(parser, token): try: From eeb374bbe84ca26dd35df486d64c94a36a166ec5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 27 Feb 2013 09:22:38 +0100 Subject: [PATCH 0627/1590] 1.7 requires Django 1.4 or better Thanks to Andi Albrecht for the pointer! --- docs/releases/1.7.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releases/1.7.rst b/docs/releases/1.7.rst index 835c053c0..aa878d539 100644 --- a/docs/releases/1.7.rst +++ b/docs/releases/1.7.rst @@ -144,4 +144,4 @@ Bugfixes Compatibility with Django and other apps ======================================== -FeinCMS 1.7 requires Django 1.4. +FeinCMS 1.7 requires Django 1.4 or better. From 6b8cd072039eef1c684ef6cd9a3fedc8582f62fe Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 28 Feb 2013 08:36:37 +0100 Subject: [PATCH 0628/1590] Move the tests out of the main app directory This project layout worked really well with Plata and Towel. --- tests/cov.sh | 2 +- tests/manage.py | 1 - {feincms => tests/testapp}/tests/__init__.py | 9 +++------ {feincms => tests/testapp}/tests/cms_tests.py | 0 {feincms => tests/testapp}/tests/page_tests.py | 7 +++++-- {feincms => tests/testapp}/tests/tests.py | 0 6 files changed, 9 insertions(+), 10 deletions(-) rename {feincms => tests/testapp}/tests/__init__.py (67%) rename {feincms => tests/testapp}/tests/cms_tests.py (100%) rename {feincms => tests/testapp}/tests/page_tests.py (99%) rename {feincms => tests/testapp}/tests/tests.py (100%) diff --git a/tests/cov.sh b/tests/cov.sh index be468fc5c..dc5800ed4 100755 --- a/tests/cov.sh +++ b/tests/cov.sh @@ -1,3 +1,3 @@ #!/bin/sh -coverage run --branch --include="*feincms*" ./manage.py test feincms +coverage run --branch --include="*feincms*" ./manage.py test testapp coverage html diff --git a/tests/manage.py b/tests/manage.py index 598b072b5..6d057f444 100755 --- a/tests/manage.py +++ b/tests/manage.py @@ -3,7 +3,6 @@ if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings") - os.environ.setdefault("FEINCMS_RUN_TESTS", "1") sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) diff --git a/feincms/tests/__init__.py b/tests/testapp/tests/__init__.py similarity index 67% rename from feincms/tests/__init__.py rename to tests/testapp/tests/__init__.py index 75f3aa027..fba82e47e 100644 --- a/feincms/tests/__init__.py +++ b/tests/testapp/tests/__init__.py @@ -4,11 +4,8 @@ from __future__ import absolute_import -import os - -if os.environ.get('FEINCMS_RUN_TESTS'): - from .cms_tests import * - from .page_tests import * - from .tests import * +from .cms_tests import * +from .page_tests import * +from .tests import * # ------------------------------------------------------------------------ diff --git a/feincms/tests/cms_tests.py b/tests/testapp/tests/cms_tests.py similarity index 100% rename from feincms/tests/cms_tests.py rename to tests/testapp/tests/cms_tests.py diff --git a/feincms/tests/page_tests.py b/tests/testapp/tests/page_tests.py similarity index 99% rename from feincms/tests/page_tests.py rename to tests/testapp/tests/page_tests.py index bf2fc602b..d70a05c1c 100644 --- a/feincms/tests/page_tests.py +++ b/tests/testapp/tests/page_tests.py @@ -1244,9 +1244,12 @@ def test_29_medialibrary_admin(self): self.assertEqual(MediaFile.objects.count(), 11, "Upload of media files with ZIP does not work") + dn = os.path.dirname + path = os.path.join(dn(dn(dn(dn(__file__)))), + 'docs', 'images', 'tree_editor.png') + self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/add/', { - 'file': open(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), - 'docs', 'images', 'tree_editor.png')), + 'file': open(path), 'translations-TOTAL_FORMS': 0, 'translations-INITIAL_FORMS': 0, 'translations-MAX_NUM_FORMS': 10, diff --git a/feincms/tests/tests.py b/tests/testapp/tests/tests.py similarity index 100% rename from feincms/tests/tests.py rename to tests/testapp/tests/tests.py From c66d3ce7cf5d5248cc0363bd89d6fdb41e9cae68 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 28 Feb 2013 08:47:45 +0100 Subject: [PATCH 0629/1590] Make the RSSContent test run faster by providing a local RSS file Refs #313. --- tests/testapp/tests/.gitattributes | 1 + tests/testapp/tests/cms_tests.py | 14 +++++++++++++- tests/testapp/tests/yahoo.rss | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/testapp/tests/.gitattributes create mode 100644 tests/testapp/tests/yahoo.rss diff --git a/tests/testapp/tests/.gitattributes b/tests/testapp/tests/.gitattributes new file mode 100644 index 000000000..9b33e0525 --- /dev/null +++ b/tests/testapp/tests/.gitattributes @@ -0,0 +1 @@ +yahoo.rss binary -diff diff --git a/tests/testapp/tests/cms_tests.py b/tests/testapp/tests/cms_tests.py index bd87e35e9..3f04bd51d 100644 --- a/tests/testapp/tests/cms_tests.py +++ b/tests/testapp/tests/cms_tests.py @@ -4,6 +4,8 @@ from __future__ import absolute_import +import os + from django.core.exceptions import ImproperlyConfigured from django.db import models from django.test import TestCase @@ -47,7 +49,17 @@ def test_01_simple_content_type_creation(self): def test_02_rsscontent_creation(self): # this test resides in its own method because the required feedparser # module is not available everywhere - from feincms.content.rss.models import RSSContent + + from feincms.content.rss.models import RSSContent, feedparser + + # Monkey-patch feedparser.parse to work with a local RSS dump so that + # the tests run faster. + _orig_parse = feedparser.parse + def _new_parse(link): + return _orig_parse( + open(os.path.join(os.path.dirname(__file__), 'yahoo.rss'))) + feedparser.parse = _new_parse + type = ExampleCMSBase.create_content_type(RSSContent) obj = type() diff --git a/tests/testapp/tests/yahoo.rss b/tests/testapp/tests/yahoo.rss new file mode 100644 index 000000000..e09803ab2 --- /dev/null +++ b/tests/testapp/tests/yahoo.rss @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0"> +<channel> +<title>World News Headlines - Yahoo! News +http://news.yahoo.com/world/ +Get the latest world news headlines from Yahoo! News. Find breaking world news, including analysis and opinion on top +world stories. +en-US +Copyright (c) 2013 Yahoo! Inc. All rights reserved +Wed, 27 Feb 2013 14:39:23 -0500 +5 + +World News Headlines - Yahoo! News +http://news.yahoo.com/world/ +http://l.yimg.com/a/i/us/nws/th/main_142c.gif + +Iran upbeat on nuclear talks, West still wary<p><a href="http://news.yahoo.com/powers-wait-hear-iran-response-nuclear-offer-043022098.html"><img src="http://l1.yimg.com/bt/api/res/1.2/MVgDDqOC_oSDJ58rMMtnnQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-27T170903Z_2_CBRE91Q0J0J00_RTROPTP_2_IRAN-NUCLEAR-PROGRESS.JPG" width="130" height="86" alt="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Jalili gestures during talks on Iran&#039;s nuclear programme in Almaty" align="left" title="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Jalili gestures during talks on Iran&#039;s nuclear programme in Almaty" border="0" /></a>ALMATY (Reuters) - Iran was upbeat on Wednesday after talks with world powers about its nuclear work ended with an agreement to meet again, but Western officials said it had yet to take concrete steps to ease their fears about its atomic ambitions. Rapid progress was unlikely with Iran&#039;s presidential election, due in June, raising domestic political tensions, diplomats and analysts had said ahead of the February 26-27 meeting in the Kazakh city of Almaty, the first in eight months. ...</p><br clear="all"/>http://news.yahoo.com/powers-wait-hear-iran-response-nuclear-offer-043022098.htmlWed, 27 Feb 2013 14:39:23 -0500Reuterspowers-wait-hear-iran-response-nuclear-offer-043022098<p><a href="http://news.yahoo.com/powers-wait-hear-iran-response-nuclear-offer-043022098.html"><img src="http://l1.yimg.com/bt/api/res/1.2/MVgDDqOC_oSDJ58rMMtnnQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-27T170903Z_2_CBRE91Q0J0J00_RTROPTP_2_IRAN-NUCLEAR-PROGRESS.JPG" width="130" height="86" alt="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Jalili gestures during talks on Iran&#039;s nuclear programme in Almaty" align="left" title="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Jalili gestures during talks on Iran&#039;s nuclear programme in Almaty" border="0" /></a>ALMATY (Reuters) - Iran was upbeat on Wednesday after talks with world powers about its nuclear work ended with an agreement to meet again, but Western officials said it had yet to take concrete steps to ease their fears about its atomic ambitions. Rapid progress was unlikely with Iran&#039;s presidential election, due in June, raising domestic political tensions, diplomats and analysts had said ahead of the February 26-27 meeting in the Kazakh city of Almaty, the first in eight months. ...</p><br clear="all"/>U.S. plans medical, food aid for Syrian rebel fighters: sources<p><a href="http://news.yahoo.com/u-plans-medical-food-aid-syrian-rebel-fighters-012612809.html"><img src="http://l.yimg.com/bt/api/res/1.2/_VZNoqIkdsh5b.Ny1HTT_w--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T012612Z_1_CBRE91R03ZS00_RTROPTP_2_SYRIA-CRISIS.JPG" width="130" height="86" alt="Members of the Free Syrian Army walk with their weapons in Deir el-Zor" align="left" title="Members of the Free Syrian Army walk with their weapons in Deir el-Zor" border="0" /></a>ROME (Reuters) - The United States plans to provide medical supplies and food to Syrian fighters, a policy shift to directly help those battling President Bashar al-Assad&#039;s forces on the ground, sources familiar with the matter said. The sources, who spoke on condition of anonymity, said the United States continues to oppose providing lethal assistance and said it also will not provide such items as bullet-proof vests, armored-personnel vehicles and military training for now. ...</p><br clear="all"/>http://news.yahoo.com/u-plans-medical-food-aid-syrian-rebel-fighters-012612809.htmlWed, 27 Feb 2013 20:26:12 -0500Reutersu-plans-medical-food-aid-syrian-rebel-fighters-012612809<p><a href="http://news.yahoo.com/u-plans-medical-food-aid-syrian-rebel-fighters-012612809.html"><img src="http://l.yimg.com/bt/api/res/1.2/_VZNoqIkdsh5b.Ny1HTT_w--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T012612Z_1_CBRE91R03ZS00_RTROPTP_2_SYRIA-CRISIS.JPG" width="130" height="86" alt="Members of the Free Syrian Army walk with their weapons in Deir el-Zor" align="left" title="Members of the Free Syrian Army walk with their weapons in Deir el-Zor" border="0" /></a>ROME (Reuters) - The United States plans to provide medical supplies and food to Syrian fighters, a policy shift to directly help those battling President Bashar al-Assad&#039;s forces on the ground, sources familiar with the matter said. The sources, who spoke on condition of anonymity, said the United States continues to oppose providing lethal assistance and said it also will not provide such items as bullet-proof vests, armored-personnel vehicles and military training for now. ...</p><br clear="all"/>Low-key departure as pope steps down and hides away<p><a href="http://news.yahoo.com/low-key-departure-pope-steps-down-hides-away-000419898.html"><img src="http://l2.yimg.com/bt/api/res/1.2/plIa_Iat2yqb5Rxfnw.TxA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T001803Z_2_CBRE91R00KV00_RTROPTP_2_POPE-RESIGNATION.JPG" width="130" height="86" alt="Pope Benedict XVI leaves after his last general audience in St Peter&#039;s Square at the Vatican" align="left" title="Pope Benedict XVI leaves after his last general audience in St Peter&#039;s Square at the Vatican" border="0" /></a>VATICAN CITY (Reuters) - Pope Benedict slips quietly from the world stage on Thursday after a private last goodbye to his cardinals and a short flight to a country palace to enter the final phase of his life &quot;hidden from the world&quot;. In keeping with his shy and modest ways, there will be no public ceremony to mark the first papal resignation in six centuries and no solemn declaration ending his nearly eight-year reign at the head of the world&#039;s largest church. ...</p><br clear="all"/>http://news.yahoo.com/low-key-departure-pope-steps-down-hides-away-000419898.htmlWed, 27 Feb 2013 19:18:03 -0500Reuterslow-key-departure-pope-steps-down-hides-away-000419898<p><a href="http://news.yahoo.com/low-key-departure-pope-steps-down-hides-away-000419898.html"><img src="http://l2.yimg.com/bt/api/res/1.2/plIa_Iat2yqb5Rxfnw.TxA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T001803Z_2_CBRE91R00KV00_RTROPTP_2_POPE-RESIGNATION.JPG" width="130" height="86" alt="Pope Benedict XVI leaves after his last general audience in St Peter&#039;s Square at the Vatican" align="left" title="Pope Benedict XVI leaves after his last general audience in St Peter&#039;s Square at the Vatican" border="0" /></a>VATICAN CITY (Reuters) - Pope Benedict slips quietly from the world stage on Thursday after a private last goodbye to his cardinals and a short flight to a country palace to enter the final phase of his life &quot;hidden from the world&quot;. In keeping with his shy and modest ways, there will be no public ceremony to mark the first papal resignation in six centuries and no solemn declaration ending his nearly eight-year reign at the head of the world&#039;s largest church. ...</p><br clear="all"/>France's Hollande juggles trade, human rights in Moscow<p><a href="http://news.yahoo.com/frances-hollande-juggles-trade-human-rights-moscow-010406942.html"><img src="http://l2.yimg.com/bt/api/res/1.2/ShUw.WTi6ZX5fMWnb8mnOw--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T010406Z_1_CBRE91R02YZ00_RTROPTP_2_CNEWS-US-RUSSIA-FRANCE.JPG" width="130" height="86" alt="France&#039;s President Hollande attends an awards ceremony at the Elysee Palace in Paris" align="left" title="France&#039;s President Hollande attends an awards ceremony at the Elysee Palace in Paris" border="0" /></a>PARIS (Reuters) - President Francois Hollande wants to boost trade ties with Moscow and will have to balance that with French concerns over Russia&#039;s human rights record during a debut Moscow visit on Thursday that could prove a diplomatic obstacle course. An encounter in Paris last June between the newly elected Socialist Hollande and Russia&#039;s Vladimir Putin bristled with tension, unlike the cosy meetings between Putin and Hollande&#039;s conservative predecessors Nicolas Sarkozy and Jacques Chirac. ...</p><br clear="all"/>http://news.yahoo.com/frances-hollande-juggles-trade-human-rights-moscow-010406942.htmlWed, 27 Feb 2013 20:04:06 -0500Reutersfrances-hollande-juggles-trade-human-rights-moscow-010406942<p><a href="http://news.yahoo.com/frances-hollande-juggles-trade-human-rights-moscow-010406942.html"><img src="http://l2.yimg.com/bt/api/res/1.2/ShUw.WTi6ZX5fMWnb8mnOw--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T010406Z_1_CBRE91R02YZ00_RTROPTP_2_CNEWS-US-RUSSIA-FRANCE.JPG" width="130" height="86" alt="France&#039;s President Hollande attends an awards ceremony at the Elysee Palace in Paris" align="left" title="France&#039;s President Hollande attends an awards ceremony at the Elysee Palace in Paris" border="0" /></a>PARIS (Reuters) - President Francois Hollande wants to boost trade ties with Moscow and will have to balance that with French concerns over Russia&#039;s human rights record during a debut Moscow visit on Thursday that could prove a diplomatic obstacle course. An encounter in Paris last June between the newly elected Socialist Hollande and Russia&#039;s Vladimir Putin bristled with tension, unlike the cosy meetings between Putin and Hollande&#039;s conservative predecessors Nicolas Sarkozy and Jacques Chirac. ...</p><br clear="all"/>Thailand agrees to talks with southern Muslim rebels<p><a href="http://news.yahoo.com/thailand-agrees-talks-southern-muslim-rebels-023853468.html"><img src="http://l1.yimg.com/bt/api/res/1.2/FutnYywa4ViXUJhaIxMxlQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T065339Z_2_CBRE91R0ABF00_RTROPTP_2_THAILAND-SOUTH.JPG" width="130" height="86" alt="Pattanathabutr of Thailand&#039;s NSC and Hassan of Thailand&#039;s BRN liason office in Malaysia shake hands as they exchange documents during a signing ceremony in Kuala Lumpur" align="left" title="Pattanathabutr of Thailand&#039;s NSC and Hassan of Thailand&#039;s BRN liason office in Malaysia shake hands as they exchange documents during a signing ceremony in Kuala Lumpur" border="0" /></a>KUALA LUMPUR, Feb 28 Reuters) - Thailand&#039;s government agreed on Thursday to start talks with a major Muslim rebel group, marking a breakthrough in efforts to end a worsening conflict in the country&#039;s south that has claimed over 5,000 lives since 2004. The agreement, signed in the Malaysian capital of Kuala Lumpur by senior Thai security officials and members of the Barisan Revolusi Nasional (BRN) group, opens the way for the first formal peace talks with rebels seeking autonomy or even a separate state in the south. ...</p><br clear="all"/>http://news.yahoo.com/thailand-agrees-talks-southern-muslim-rebels-023853468.htmlThu, 28 Feb 2013 01:53:39 -0500Reutersthailand-agrees-talks-southern-muslim-rebels-023853468<p><a href="http://news.yahoo.com/thailand-agrees-talks-southern-muslim-rebels-023853468.html"><img src="http://l1.yimg.com/bt/api/res/1.2/FutnYywa4ViXUJhaIxMxlQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T065339Z_2_CBRE91R0ABF00_RTROPTP_2_THAILAND-SOUTH.JPG" width="130" height="86" alt="Pattanathabutr of Thailand&#039;s NSC and Hassan of Thailand&#039;s BRN liason office in Malaysia shake hands as they exchange documents during a signing ceremony in Kuala Lumpur" align="left" title="Pattanathabutr of Thailand&#039;s NSC and Hassan of Thailand&#039;s BRN liason office in Malaysia shake hands as they exchange documents during a signing ceremony in Kuala Lumpur" border="0" /></a>KUALA LUMPUR, Feb 28 Reuters) - Thailand&#039;s government agreed on Thursday to start talks with a major Muslim rebel group, marking a breakthrough in efforts to end a worsening conflict in the country&#039;s south that has claimed over 5,000 lives since 2004. The agreement, signed in the Malaysian capital of Kuala Lumpur by senior Thai security officials and members of the Barisan Revolusi Nasional (BRN) group, opens the way for the first formal peace talks with rebels seeking autonomy or even a separate state in the south. ...</p><br clear="all"/>Indonesia finance minister says no political pressure to oust him<p><a href="http://news.yahoo.com/indonesia-finance-minister-says-no-political-pressure-oust-063958270--business.html"><img src="http://l2.yimg.com/bt/api/res/1.2/cRQJX_wqE7YAGylvZ562xw--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T063958Z_1_CBRE91R0IIR00_RTROPTP_2_INDONESIA-CENTRALBANK-MARTOWARDOJO.JPG" width="130" height="86" alt="Indonesian Finance Minister Martowardojo leaves the presidential compound after attending a meeting in Jakarta" align="left" title="Indonesian Finance Minister Martowardojo leaves the presidential compound after attending a meeting in Jakarta" border="0" /></a>JAKARTA (Reuters) - Indonesia&#039;s finance minister denied on Thursday that he was being pushed out his job, dismissing speculation that he was being shifted to the post of central bank governor because he had crossed swords with politically powerful businessmen. President Susilo Bambang Yudhoyono unexpectedly nominated Finance Minister Agus Martowardojo to replace Darmin Nasution, whose term as Bank Indonesia governor ends in May. ...</p><br clear="all"/>http://news.yahoo.com/indonesia-finance-minister-says-no-political-pressure-oust-063958270--business.htmlThu, 28 Feb 2013 01:39:58 -0500Reutersindonesia-finance-minister-says-no-political-pressure-oust-063958270--business<p><a href="http://news.yahoo.com/indonesia-finance-minister-says-no-political-pressure-oust-063958270--business.html"><img src="http://l2.yimg.com/bt/api/res/1.2/cRQJX_wqE7YAGylvZ562xw--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T063958Z_1_CBRE91R0IIR00_RTROPTP_2_INDONESIA-CENTRALBANK-MARTOWARDOJO.JPG" width="130" height="86" alt="Indonesian Finance Minister Martowardojo leaves the presidential compound after attending a meeting in Jakarta" align="left" title="Indonesian Finance Minister Martowardojo leaves the presidential compound after attending a meeting in Jakarta" border="0" /></a>JAKARTA (Reuters) - Indonesia&#039;s finance minister denied on Thursday that he was being pushed out his job, dismissing speculation that he was being shifted to the post of central bank governor because he had crossed swords with politically powerful businessmen. President Susilo Bambang Yudhoyono unexpectedly nominated Finance Minister Agus Martowardojo to replace Darmin Nasution, whose term as Bank Indonesia governor ends in May. ...</p><br clear="all"/>Japan PM Abe cites Thatcher reflections on Falklands war<p><a href="http://news.yahoo.com/japan-pm-abe-cites-thatcher-reflections-falklands-war-042224117.html"><img src="http://l3.yimg.com/bt/api/res/1.2/005HWz_v688ZkZqfZVdPPA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T042224Z_1_CBRE91R0C5J00_RTROPTP_2_CNEWS-US-JAPAN-CHINA-THATCHER.JPG" width="130" height="86" alt="Japan&#039;s Prime Minister Shinzo Abe attends a meeting with President of Kyrgyzstan Almazbek Atambayev (not in picture) at Abe&#039;s official residence in Tokyo" align="left" title="Japan&#039;s Prime Minister Shinzo Abe attends a meeting with President of Kyrgyzstan Almazbek Atambayev (not in picture) at Abe&#039;s official residence in Tokyo" border="0" /></a>TOKYO (Reuters) - Japanese Prime Minister Shinzo Abe, whose country is embroiled in a row with China over tiny islands, on Thursday quoted former British Prime Minister Margaret Thatcher&#039;s reflections on the 1982 Falklands war with Argentina to stress the importance of the rule of law at sea. &quot;Our national interests have been immutable. They lie in making the seas, which are the foundation of our nation&#039;s existence, completely open, free and peaceful,&quot; Abe said in a prepared policy speech to parliament covering a wide range of issues. ...</p><br clear="all"/>http://news.yahoo.com/japan-pm-abe-cites-thatcher-reflections-falklands-war-042224117.htmlWed, 27 Feb 2013 23:22:24 -0500Reutersjapan-pm-abe-cites-thatcher-reflections-falklands-war-042224117<p><a href="http://news.yahoo.com/japan-pm-abe-cites-thatcher-reflections-falklands-war-042224117.html"><img src="http://l3.yimg.com/bt/api/res/1.2/005HWz_v688ZkZqfZVdPPA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T042224Z_1_CBRE91R0C5J00_RTROPTP_2_CNEWS-US-JAPAN-CHINA-THATCHER.JPG" width="130" height="86" alt="Japan&#039;s Prime Minister Shinzo Abe attends a meeting with President of Kyrgyzstan Almazbek Atambayev (not in picture) at Abe&#039;s official residence in Tokyo" align="left" title="Japan&#039;s Prime Minister Shinzo Abe attends a meeting with President of Kyrgyzstan Almazbek Atambayev (not in picture) at Abe&#039;s official residence in Tokyo" border="0" /></a>TOKYO (Reuters) - Japanese Prime Minister Shinzo Abe, whose country is embroiled in a row with China over tiny islands, on Thursday quoted former British Prime Minister Margaret Thatcher&#039;s reflections on the 1982 Falklands war with Argentina to stress the importance of the rule of law at sea. &quot;Our national interests have been immutable. They lie in making the seas, which are the foundation of our nation&#039;s existence, completely open, free and peaceful,&quot; Abe said in a prepared policy speech to parliament covering a wide range of issues. ...</p><br clear="all"/>Battling a scandal, Britain's deputy PM under pressure in vote<p><a href="http://news.yahoo.com/battling-scandal-britains-deputy-pm-under-pressure-vote-010614690.html"><img src="http://l3.yimg.com/bt/api/res/1.2/hBZc6Xaudi20dw2A_AktrA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T010614Z_1_CBRE91R032I00_RTROPTP_2_BRITAIN.JPG" width="130" height="86" alt="Britain&#039;s deputy Prime Minister Nick Clegg arrives to take part in a phone-in show at a radio station in London" align="left" title="Britain&#039;s deputy Prime Minister Nick Clegg arrives to take part in a phone-in show at a radio station in London" border="0" /></a>LONDON (Reuters) - Fewer than 100,000 residents of an English town that hardly anyone outside Britain has heard of will vote on Thursday in an election that could help determine the political fate of the country&#039;s deputy prime minister and, ultimately, its government. The poll to choose a member of parliament for Eastleigh may prove make-or-break for Nick Clegg&#039;s leadership of the Liberal Democrats, the junior member of Britain&#039;s two-party coalition. &quot;Most by-elections are events of only fleeting interest. Some are sufficiently dramatic to linger a while in the memory. Only a few truly matter. ...</p><br clear="all"/>http://news.yahoo.com/battling-scandal-britains-deputy-pm-under-pressure-vote-010614690.htmlWed, 27 Feb 2013 20:06:14 -0500Reutersbattling-scandal-britains-deputy-pm-under-pressure-vote-010614690<p><a href="http://news.yahoo.com/battling-scandal-britains-deputy-pm-under-pressure-vote-010614690.html"><img src="http://l3.yimg.com/bt/api/res/1.2/hBZc6Xaudi20dw2A_AktrA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T010614Z_1_CBRE91R032I00_RTROPTP_2_BRITAIN.JPG" width="130" height="86" alt="Britain&#039;s deputy Prime Minister Nick Clegg arrives to take part in a phone-in show at a radio station in London" align="left" title="Britain&#039;s deputy Prime Minister Nick Clegg arrives to take part in a phone-in show at a radio station in London" border="0" /></a>LONDON (Reuters) - Fewer than 100,000 residents of an English town that hardly anyone outside Britain has heard of will vote on Thursday in an election that could help determine the political fate of the country&#039;s deputy prime minister and, ultimately, its government. The poll to choose a member of parliament for Eastleigh may prove make-or-break for Nick Clegg&#039;s leadership of the Liberal Democrats, the junior member of Britain&#039;s two-party coalition. &quot;Most by-elections are events of only fleeting interest. Some are sufficiently dramatic to linger a while in the memory. Only a few truly matter. ...</p><br clear="all"/>Yemen kidnappers free Swiss woman after Qatari mediation: agency<p><a href="http://news.yahoo.com/yemen-kidnappers-free-swiss-woman-qatari-mediation-agency-050803897.html"><img src="http://l1.yimg.com/bt/api/res/1.2/ks.UUCAIJNw_frBXqMH5HA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3B4b2ZmPTUwO3B5b2ZmPTA7cT04NTt3PTEzMA--/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T060204Z_1_CBRE91R0GRJ00_RTROPTP_2_QATAR-SWITZERLAND-HOSTAGE.JPG" width="130" height="86" alt="Swiss teacher Abrahat, who was kidnapped in Yemen, arrives in Doha after she was freed" align="left" title="Swiss teacher Abrahat, who was kidnapped in Yemen, arrives in Doha after she was freed" border="0" /></a>DOHA (Reuters) - A Swiss woman held hostage for nearly a year in Yemen has been freed by her kidnappers and flown to Doha following mediation by Qatar, the Qatari state news agency QNA reported late on Wednesday. Armed tribesmen had kidnapped the teacher in the western Yemeni port city of Hudaida in March 2012 to press their government to free jailed relatives, a Yemeni Interior Ministry official told Reuters last year. ...</p><br clear="all"/>http://news.yahoo.com/yemen-kidnappers-free-swiss-woman-qatari-mediation-agency-050803897.htmlThu, 28 Feb 2013 01:02:04 -0500Reutersyemen-kidnappers-free-swiss-woman-qatari-mediation-agency-050803897<p><a href="http://news.yahoo.com/yemen-kidnappers-free-swiss-woman-qatari-mediation-agency-050803897.html"><img src="http://l1.yimg.com/bt/api/res/1.2/ks.UUCAIJNw_frBXqMH5HA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3B4b2ZmPTUwO3B5b2ZmPTA7cT04NTt3PTEzMA--/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T060204Z_1_CBRE91R0GRJ00_RTROPTP_2_QATAR-SWITZERLAND-HOSTAGE.JPG" width="130" height="86" alt="Swiss teacher Abrahat, who was kidnapped in Yemen, arrives in Doha after she was freed" align="left" title="Swiss teacher Abrahat, who was kidnapped in Yemen, arrives in Doha after she was freed" border="0" /></a>DOHA (Reuters) - A Swiss woman held hostage for nearly a year in Yemen has been freed by her kidnappers and flown to Doha following mediation by Qatar, the Qatari state news agency QNA reported late on Wednesday. Armed tribesmen had kidnapped the teacher in the western Yemeni port city of Hudaida in March 2012 to press their government to free jailed relatives, a Yemeni Interior Ministry official told Reuters last year. ...</p><br clear="all"/>Mexican union boss arrest sounds warning to reform foes<p><a href="http://news.yahoo.com/mexican-union-boss-arrest-sounds-warning-reform-foes-041320615.html"><img src="http://l3.yimg.com/bt/api/res/1.2/vveOPWKC2ZtdeCOlPH0eHQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T041320Z_2_CBRE91Q1OIE00_RTROPTP_2_MEXICO-EDUCATION-PENANIETO.JPG" width="130" height="86" alt="Elba Esther Gordillo, leader of Mexico&#039;s teacher&#039;s union, is seen on a television screen during the closed-circuit broadcast of her judicial hearing inside a court in Mexico City" align="left" title="Elba Esther Gordillo, leader of Mexico&#039;s teacher&#039;s union, is seen on a television screen during the closed-circuit broadcast of her judicial hearing inside a court in Mexico City" border="0" /></a>MEXICO CITY (Reuters) - The arrest of Mexico&#039;s best-known trade union leader on fraud charges has thrown down the gauntlet to powerful interests standing between President Enrique Pena Nieto and his plans to shake up Latin America&#039;s second-biggest economy. For a generation, even presidents shied away from taking on teachers&#039; union boss Elba Esther Gordillo, making her Mexico&#039;s most prominent female politician and a formidable enemy to those who accused her of fostering corruption rather than education. ...</p><br clear="all"/>http://news.yahoo.com/mexican-union-boss-arrest-sounds-warning-reform-foes-041320615.htmlWed, 27 Feb 2013 23:13:20 -0500Reutersmexican-union-boss-arrest-sounds-warning-reform-foes-041320615<p><a href="http://news.yahoo.com/mexican-union-boss-arrest-sounds-warning-reform-foes-041320615.html"><img src="http://l3.yimg.com/bt/api/res/1.2/vveOPWKC2ZtdeCOlPH0eHQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-02-28T041320Z_2_CBRE91Q1OIE00_RTROPTP_2_MEXICO-EDUCATION-PENANIETO.JPG" width="130" height="86" alt="Elba Esther Gordillo, leader of Mexico&#039;s teacher&#039;s union, is seen on a television screen during the closed-circuit broadcast of her judicial hearing inside a court in Mexico City" align="left" title="Elba Esther Gordillo, leader of Mexico&#039;s teacher&#039;s union, is seen on a television screen during the closed-circuit broadcast of her judicial hearing inside a court in Mexico City" border="0" /></a>MEXICO CITY (Reuters) - The arrest of Mexico&#039;s best-known trade union leader on fraud charges has thrown down the gauntlet to powerful interests standing between President Enrique Pena Nieto and his plans to shake up Latin America&#039;s second-biggest economy. For a generation, even presidents shied away from taking on teachers&#039; union boss Elba Esther Gordillo, making her Mexico&#039;s most prominent female politician and a formidable enemy to those who accused her of fostering corruption rather than education. ...</p><br clear="all"/>Terrorized ethnic group to form force in Pakistan<p><a href="http://news.yahoo.com/terrorized-ethnic-group-form-force-pakistan-064954081.html"><img src="http://l2.yimg.com/bt/api/res/1.2/GxclZJuOcvYeXBoYtexCMQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/dc6bdfe30438bb072a0f6a706700ba06.jpg" width="130" height="86" alt="In this Thursday, Feb. 21, 2013, photo, Pakistani Shiite Muslim children hold candles and banners next to photographs of people, who were killed by a bomb blast in market on Saturday, February 16, 2013, in Quetta, Pakistan. Terrorized by ferocious attacks that have killed nearly 400 ethnic Hazaras in the past 18 months, with almost half of those deaths occurring in the first two months of this year, Shiite leaders blamed the inaction of Pakistan’s security service for the rising violence against them in Quetta, the capital of southwestern Baluchistan province.(AP Photo/Arshad Butt)" align="left" title="In this Thursday, Feb. 21, 2013, photo, Pakistani Shiite Muslim children hold candles and banners next to photographs of people, who were killed by a bomb blast in market on Saturday, February 16, 2013, in Quetta, Pakistan. Terrorized by ferocious attacks that have killed nearly 400 ethnic Hazaras in the past 18 months, with almost half of those deaths occurring in the first two months of this year, Shiite leaders blamed the inaction of Pakistan’s security service for the rising violence against them in Quetta, the capital of southwestern Baluchistan province.(AP Photo/Arshad Butt)" border="0" /></a>QUETTA, Pakistan (AP) — Inside the ruins of a market demolished by a powerful bomb, four tiny white candles —dwarfed by the scale of the destruction — flickered gently in the freezing rain as dazed Shiite Muslim Hazaras wept for the nearly 90 people killed in the blast.</p><br clear="all"/>http://news.yahoo.com/terrorized-ethnic-group-form-force-pakistan-064954081.htmlThu, 28 Feb 2013 01:49:54 -0500Associated Pressterrorized-ethnic-group-form-force-pakistan-064954081<p><a href="http://news.yahoo.com/terrorized-ethnic-group-form-force-pakistan-064954081.html"><img src="http://l2.yimg.com/bt/api/res/1.2/GxclZJuOcvYeXBoYtexCMQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/dc6bdfe30438bb072a0f6a706700ba06.jpg" width="130" height="86" alt="In this Thursday, Feb. 21, 2013, photo, Pakistani Shiite Muslim children hold candles and banners next to photographs of people, who were killed by a bomb blast in market on Saturday, February 16, 2013, in Quetta, Pakistan. Terrorized by ferocious attacks that have killed nearly 400 ethnic Hazaras in the past 18 months, with almost half of those deaths occurring in the first two months of this year, Shiite leaders blamed the inaction of Pakistan’s security service for the rising violence against them in Quetta, the capital of southwestern Baluchistan province.(AP Photo/Arshad Butt)" align="left" title="In this Thursday, Feb. 21, 2013, photo, Pakistani Shiite Muslim children hold candles and banners next to photographs of people, who were killed by a bomb blast in market on Saturday, February 16, 2013, in Quetta, Pakistan. Terrorized by ferocious attacks that have killed nearly 400 ethnic Hazaras in the past 18 months, with almost half of those deaths occurring in the first two months of this year, Shiite leaders blamed the inaction of Pakistan’s security service for the rising violence against them in Quetta, the capital of southwestern Baluchistan province.(AP Photo/Arshad Butt)" border="0" /></a>QUETTA, Pakistan (AP) — Inside the ruins of a market demolished by a powerful bomb, four tiny white candles —dwarfed by the scale of the destruction — flickered gently in the freezing rain as dazed Shiite Muslim Hazaras wept for the nearly 90 people killed in the blast.</p><br clear="all"/>Pope legacy: Teacher who returned to church roots<p><a href="http://news.yahoo.com/pope-legacy-teacher-returned-church-roots-191501542.html"><img src="http://l3.yimg.com/bt/api/res/1.2/Jed9DcVNtqDogvpiJk0ECg--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/a02a50ea03fbb9072a0f6a706700a86e.jpg" width="130" height="86" alt="FILE - This Sept. 6, 2006 file photo shows Pope Benedict XVI wearing a &quot;saturno hat&quot;, inspired by the ringed planet Saturn, to shield himself from the sun as he waves to the crowd of faithful prior to his weekly general audience in St. Peter&#039;s Square at the Vatican. (AP Photo/Pier Paolo Cito, files)" align="left" title="FILE - This Sept. 6, 2006 file photo shows Pope Benedict XVI wearing a &quot;saturno hat&quot;, inspired by the ringed planet Saturn, to shield himself from the sun as he waves to the crowd of faithful prior to his weekly general audience in St. Peter&#039;s Square at the Vatican. (AP Photo/Pier Paolo Cito, files)" border="0" /></a>VATICAN CITY (AP) — On Monday, April 4, 2005, a priest walked up to the Renaissance palazzo housing the Vatican&#039;s doctrine department and asked the doorman to call the official in charge: It was the first day of business after Pope John Paul II had died, and the cleric wanted to get back to work.</p><br clear="all"/>http://news.yahoo.com/pope-legacy-teacher-returned-church-roots-191501542.htmlThu, 28 Feb 2013 01:15:09 -0500Associated Presspope-legacy-teacher-returned-church-roots-191501542<p><a href="http://news.yahoo.com/pope-legacy-teacher-returned-church-roots-191501542.html"><img src="http://l3.yimg.com/bt/api/res/1.2/Jed9DcVNtqDogvpiJk0ECg--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/a02a50ea03fbb9072a0f6a706700a86e.jpg" width="130" height="86" alt="FILE - This Sept. 6, 2006 file photo shows Pope Benedict XVI wearing a &quot;saturno hat&quot;, inspired by the ringed planet Saturn, to shield himself from the sun as he waves to the crowd of faithful prior to his weekly general audience in St. Peter&#039;s Square at the Vatican. (AP Photo/Pier Paolo Cito, files)" align="left" title="FILE - This Sept. 6, 2006 file photo shows Pope Benedict XVI wearing a &quot;saturno hat&quot;, inspired by the ringed planet Saturn, to shield himself from the sun as he waves to the crowd of faithful prior to his weekly general audience in St. Peter&#039;s Square at the Vatican. (AP Photo/Pier Paolo Cito, files)" border="0" /></a>VATICAN CITY (AP) — On Monday, April 4, 2005, a priest walked up to the Renaissance palazzo housing the Vatican&#039;s doctrine department and asked the doorman to call the official in charge: It was the first day of business after Pope John Paul II had died, and the cleric wanted to get back to work.</p><br clear="all"/>Hollande to talk Syria settlement with PutinMOSCOW (AP) — French President Francois Hollande said Thursday that he hopes to discuss political transition in war-torn Syria with Russian President Vladimir Putin, whose stance on Syria is crucial to hopes for a peace settlement.http://news.yahoo.com/hollande-talk-syria-settlement-putin-060512520.htmlThu, 28 Feb 2013 02:20:08 -0500Associated Presshollande-talk-syria-settlement-putin-060512520Benedict begins final day as pope before retiringVATICAN CITY (AP) — Pope Benedict XVI is beginning a final quiet day as pontiff, meeting with his cardinals before flying off into retirement.http://news.yahoo.com/benedict-begins-final-day-pope-retiring-072142573.htmlThu, 28 Feb 2013 02:21:42 -0500Associated Pressbenedict-begins-final-day-pope-retiring-072142573AP INTERVIEW: Iraq PM warns Syria war could spread<p><a href="http://news.yahoo.com/ap-interview-iraq-pm-warns-syria-war-could-150040420.html"><img src="http://l3.yimg.com/bt/api/res/1.2/n14Xgo_PEERctD87NBTjNA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/1417f2c702e0b4072a0f6a706700fd86.jpg" width="130" height="86" alt="Iraq&#039;s Prime Minister Nouri al-Maliki listens during an interview with The Associated Press in Baghdad, Iraq, Wednesday, Feb. 27, 2013. Al-Maliki warns that a victory for rebels fighting to overthrow the Syrian President Bashar Assad would spark a sectarian war in his own country and Lebanon, and create a new haven for extremists that would destabilize the wider Middle East. (AP Photo/ Khalid Mohammed)" align="left" title="Iraq&#039;s Prime Minister Nouri al-Maliki listens during an interview with The Associated Press in Baghdad, Iraq, Wednesday, Feb. 27, 2013. Al-Maliki warns that a victory for rebels fighting to overthrow the Syrian President Bashar Assad would spark a sectarian war in his own country and Lebanon, and create a new haven for extremists that would destabilize the wider Middle East. (AP Photo/ Khalid Mohammed)" border="0" /></a>BAGHDAD (AP) — Iraq&#039;s prime minister warned Wednesday that a victory for rebels in the Syrian civil war would create a new extremist haven and destabilize the wider Middle East, sparking sectarian wars in his own country and in Lebanon.</p><br clear="all"/>http://news.yahoo.com/ap-interview-iraq-pm-warns-syria-war-could-150040420.htmlWed, 27 Feb 2013 16:39:53 -0500Associated Pressap-interview-iraq-pm-warns-syria-war-could-150040420<p><a href="http://news.yahoo.com/ap-interview-iraq-pm-warns-syria-war-could-150040420.html"><img src="http://l3.yimg.com/bt/api/res/1.2/n14Xgo_PEERctD87NBTjNA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/1417f2c702e0b4072a0f6a706700fd86.jpg" width="130" height="86" alt="Iraq&#039;s Prime Minister Nouri al-Maliki listens during an interview with The Associated Press in Baghdad, Iraq, Wednesday, Feb. 27, 2013. Al-Maliki warns that a victory for rebels fighting to overthrow the Syrian President Bashar Assad would spark a sectarian war in his own country and Lebanon, and create a new haven for extremists that would destabilize the wider Middle East. (AP Photo/ Khalid Mohammed)" align="left" title="Iraq&#039;s Prime Minister Nouri al-Maliki listens during an interview with The Associated Press in Baghdad, Iraq, Wednesday, Feb. 27, 2013. Al-Maliki warns that a victory for rebels fighting to overthrow the Syrian President Bashar Assad would spark a sectarian war in his own country and Lebanon, and create a new haven for extremists that would destabilize the wider Middle East. (AP Photo/ Khalid Mohammed)" border="0" /></a>BAGHDAD (AP) — Iraq&#039;s prime minister warned Wednesday that a victory for rebels in the Syrian civil war would create a new extremist haven and destabilize the wider Middle East, sparking sectarian wars in his own country and in Lebanon.</p><br clear="all"/>Tweets, pics give real-time peek into North Korea<p><a href="http://news.yahoo.com/tweets-pics-real-time-peek-north-korea-022041602.html"><img src="http://l2.yimg.com/bt/api/res/1.2/v_80_X1SAj7KzC28jopFLg--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3B4b2ZmPTUwO3B5b2ZmPTA7cT04NTt3PTEzMA--/http://media.zenfs.com/en_us/News/ap_webfeeds/3e7b31eb1fcbc3072a0f6a706700a917.jpg" width="130" height="86" alt="In this Feb. 16, 2013 photo taken with an iPhone and posted to Instagram on Feb. 16 , 2013, North Korean school boys play with an Associated Press photographer&#039;s professional camera in front of statues of the late leaders Kim Il Sung and Kim Jong Il, on Mansu Hill in Pyongyang, North Korea. On Jan. 18, 2013, foreigners were allowed for the first time to bring mobile phones into North Korea. And this week the local service provider, Koryolink, is allowing foreigners to access the Internet on a data capable 3G connection on mobile phones.(AP Photo/David Guttenfelder)" align="left" title="In this Feb. 16, 2013 photo taken with an iPhone and posted to Instagram on Feb. 16 , 2013, North Korean school boys play with an Associated Press photographer&#039;s professional camera in front of statues of the late leaders Kim Il Sung and Kim Jong Il, on Mansu Hill in Pyongyang, North Korea. On Jan. 18, 2013, foreigners were allowed for the first time to bring mobile phones into North Korea. And this week the local service provider, Koryolink, is allowing foreigners to access the Internet on a data capable 3G connection on mobile phones.(AP Photo/David Guttenfelder)" border="0" /></a>&quot;Hello world from comms center in (hash)Pyongyang.&quot;</p><br clear="all"/>http://news.yahoo.com/tweets-pics-real-time-peek-north-korea-022041602.htmlWed, 27 Feb 2013 23:53:35 -0500Associated Presstweets-pics-real-time-peek-north-korea-022041602<p><a href="http://news.yahoo.com/tweets-pics-real-time-peek-north-korea-022041602.html"><img src="http://l2.yimg.com/bt/api/res/1.2/v_80_X1SAj7KzC28jopFLg--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3B4b2ZmPTUwO3B5b2ZmPTA7cT04NTt3PTEzMA--/http://media.zenfs.com/en_us/News/ap_webfeeds/3e7b31eb1fcbc3072a0f6a706700a917.jpg" width="130" height="86" alt="In this Feb. 16, 2013 photo taken with an iPhone and posted to Instagram on Feb. 16 , 2013, North Korean school boys play with an Associated Press photographer&#039;s professional camera in front of statues of the late leaders Kim Il Sung and Kim Jong Il, on Mansu Hill in Pyongyang, North Korea. On Jan. 18, 2013, foreigners were allowed for the first time to bring mobile phones into North Korea. And this week the local service provider, Koryolink, is allowing foreigners to access the Internet on a data capable 3G connection on mobile phones.(AP Photo/David Guttenfelder)" align="left" title="In this Feb. 16, 2013 photo taken with an iPhone and posted to Instagram on Feb. 16 , 2013, North Korean school boys play with an Associated Press photographer&#039;s professional camera in front of statues of the late leaders Kim Il Sung and Kim Jong Il, on Mansu Hill in Pyongyang, North Korea. On Jan. 18, 2013, foreigners were allowed for the first time to bring mobile phones into North Korea. And this week the local service provider, Koryolink, is allowing foreigners to access the Internet on a data capable 3G connection on mobile phones.(AP Photo/David Guttenfelder)" border="0" /></a>&quot;Hello world from comms center in (hash)Pyongyang.&quot;</p><br clear="all"/>Mexico plays hardball in jailing of union boss<p><a href="http://news.yahoo.com/mexico-plays-hardball-jailing-union-boss-223212967.html"><img src="http://l2.yimg.com/bt/api/res/1.2/vOchtpcaQA.hohsnoOqlrA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/4c4a88a004e7be072a0f6a7067007057.jpg" width="130" height="86" alt="In this photo released by Mexico&#039;s federal court system, the head of Mexico&#039;s powerful teachers&#039; union, Elba Esther Gordillo, stands behind bars as she appears for a hearing at a federal prison in Mexico City, Wednesday, Feb. 27, 2013. Mexico&#039;s most powerful woman was formally charged with a massive embezzlement scheme on Wednesday, standing grim-faced behind bars live on national television in what many called a clear message that the new government is asserting its authority. (AP Photo/Juzgado Sexto de Distrito en Procesos Penales Federales)" align="left" title="In this photo released by Mexico&#039;s federal court system, the head of Mexico&#039;s powerful teachers&#039; union, Elba Esther Gordillo, stands behind bars as she appears for a hearing at a federal prison in Mexico City, Wednesday, Feb. 27, 2013. Mexico&#039;s most powerful woman was formally charged with a massive embezzlement scheme on Wednesday, standing grim-faced behind bars live on national television in what many called a clear message that the new government is asserting its authority. (AP Photo/Juzgado Sexto de Distrito en Procesos Penales Federales)" border="0" /></a>MEXICO CITY (AP) — The arrest of Mexico&#039;s most powerful union leader echoes the hardball tactics of Mexico&#039;s once-imperial presidency while pushing forward an education reform that Enrique Pena Nieto has made a centerpiece of his new administration.</p><br clear="all"/>http://news.yahoo.com/mexico-plays-hardball-jailing-union-boss-223212967.htmlWed, 27 Feb 2013 23:42:48 -0500Associated Pressmexico-plays-hardball-jailing-union-boss-223212967<p><a href="http://news.yahoo.com/mexico-plays-hardball-jailing-union-boss-223212967.html"><img src="http://l2.yimg.com/bt/api/res/1.2/vOchtpcaQA.hohsnoOqlrA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/4c4a88a004e7be072a0f6a7067007057.jpg" width="130" height="86" alt="In this photo released by Mexico&#039;s federal court system, the head of Mexico&#039;s powerful teachers&#039; union, Elba Esther Gordillo, stands behind bars as she appears for a hearing at a federal prison in Mexico City, Wednesday, Feb. 27, 2013. Mexico&#039;s most powerful woman was formally charged with a massive embezzlement scheme on Wednesday, standing grim-faced behind bars live on national television in what many called a clear message that the new government is asserting its authority. (AP Photo/Juzgado Sexto de Distrito en Procesos Penales Federales)" align="left" title="In this photo released by Mexico&#039;s federal court system, the head of Mexico&#039;s powerful teachers&#039; union, Elba Esther Gordillo, stands behind bars as she appears for a hearing at a federal prison in Mexico City, Wednesday, Feb. 27, 2013. Mexico&#039;s most powerful woman was formally charged with a massive embezzlement scheme on Wednesday, standing grim-faced behind bars live on national television in what many called a clear message that the new government is asserting its authority. (AP Photo/Juzgado Sexto de Distrito en Procesos Penales Federales)" border="0" /></a>MEXICO CITY (AP) — The arrest of Mexico&#039;s most powerful union leader echoes the hardball tactics of Mexico&#039;s once-imperial presidency while pushing forward an education reform that Enrique Pena Nieto has made a centerpiece of his new administration.</p><br clear="all"/>US, Europe move to expand role in Syrian conflict<p><a href="http://news.yahoo.com/us-europe-move-expand-role-syrian-conflict-210542972--politics.html"><img src="http://l1.yimg.com/bt/api/res/1.2/xrlu09OnHQutG6_zrCylbQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/81138a39043abb072a0f6a706700ed14.jpg" width="130" height="86" alt="This photo taken Feb. 27, 2013 shows Secretary of State John Kerry arriving at the Foreign Ministry in Paris. The U.S. is moving closer to direct involvement in Syria’s civil war with the delivery of non-lethal assistance directly to the rebels fighting President Bashar Assad’s regime. Officials say the decision to offer ready-made meals and medical supplies to the rebels may be a step toward eventual U.S. military aid, which the administration has so far resisted. (AP Photo/Jacquelyn Martin, Pool)" align="left" title="This photo taken Feb. 27, 2013 shows Secretary of State John Kerry arriving at the Foreign Ministry in Paris. The U.S. is moving closer to direct involvement in Syria’s civil war with the delivery of non-lethal assistance directly to the rebels fighting President Bashar Assad’s regime. Officials say the decision to offer ready-made meals and medical supplies to the rebels may be a step toward eventual U.S. military aid, which the administration has so far resisted. (AP Photo/Jacquelyn Martin, Pool)" border="0" /></a>ROME (AP) — The United States and some European allies are edging closer to direct involvement in Syria&#039;s civil war with plans to deliver meals, medical kits and other forms of nonlethal assistance to the rebels battling President Bashar Assad.</p><br clear="all"/>http://news.yahoo.com/us-europe-move-expand-role-syrian-conflict-210542972--politics.htmlWed, 27 Feb 2013 17:29:58 -0500Associated Pressus-europe-move-expand-role-syrian-conflict-210542972--politics<p><a href="http://news.yahoo.com/us-europe-move-expand-role-syrian-conflict-210542972--politics.html"><img src="http://l1.yimg.com/bt/api/res/1.2/xrlu09OnHQutG6_zrCylbQ--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/81138a39043abb072a0f6a706700ed14.jpg" width="130" height="86" alt="This photo taken Feb. 27, 2013 shows Secretary of State John Kerry arriving at the Foreign Ministry in Paris. The U.S. is moving closer to direct involvement in Syria’s civil war with the delivery of non-lethal assistance directly to the rebels fighting President Bashar Assad’s regime. Officials say the decision to offer ready-made meals and medical supplies to the rebels may be a step toward eventual U.S. military aid, which the administration has so far resisted. (AP Photo/Jacquelyn Martin, Pool)" align="left" title="This photo taken Feb. 27, 2013 shows Secretary of State John Kerry arriving at the Foreign Ministry in Paris. The U.S. is moving closer to direct involvement in Syria’s civil war with the delivery of non-lethal assistance directly to the rebels fighting President Bashar Assad’s regime. Officials say the decision to offer ready-made meals and medical supplies to the rebels may be a step toward eventual U.S. military aid, which the administration has so far resisted. (AP Photo/Jacquelyn Martin, Pool)" border="0" /></a>ROME (AP) — The United States and some European allies are edging closer to direct involvement in Syria&#039;s civil war with plans to deliver meals, medical kits and other forms of nonlethal assistance to the rebels battling President Bashar Assad.</p><br clear="all"/>World powers coax Iran into saving nuclear talks<p><a href="http://news.yahoo.com/world-powers-coax-iran-saving-nuclear-talks-165127448.html"><img src="http://l2.yimg.com/bt/api/res/1.2/UgeB3NSuqsL1VJWIpTa6Rw--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/5f51a25e036ab7072a0f6a706700500b.jpg" width="130" height="86" alt="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Saeed Jalili listens to a question during a final news conference in Almaty, Kazakhstan, Wednesday, Feb. 27, 2013. Negotiations with world powers over how to curb Iran&#039;s nuclear program have reached a &quot;turning point&quot; for the better after nearly breaking down last year, the Islamic republic&#039;s top official at diplomatic talks said Wednesday at the close of two days of delicate discussions aimed at preventing Tehran from building an atomic arsenal. (AP Photo/Pavel Mikheyev)" align="left" title="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Saeed Jalili listens to a question during a final news conference in Almaty, Kazakhstan, Wednesday, Feb. 27, 2013. Negotiations with world powers over how to curb Iran&#039;s nuclear program have reached a &quot;turning point&quot; for the better after nearly breaking down last year, the Islamic republic&#039;s top official at diplomatic talks said Wednesday at the close of two days of delicate discussions aimed at preventing Tehran from building an atomic arsenal. (AP Photo/Pavel Mikheyev)" border="0" /></a>ALMATY, Kazakhstan (AP) — World powers offered broader concessions than ever to Iran in attempts Wednesday to keep alive diplomatic channels that seek to rein in the Islamic Republic&#039;s nuclear program and prevent it from building an atomic weapon.</p><br clear="all"/>http://news.yahoo.com/world-powers-coax-iran-saving-nuclear-talks-165127448.htmlWed, 27 Feb 2013 17:56:54 -0500Associated Pressworld-powers-coax-iran-saving-nuclear-talks-165127448<p><a href="http://news.yahoo.com/world-powers-coax-iran-saving-nuclear-talks-165127448.html"><img src="http://l2.yimg.com/bt/api/res/1.2/UgeB3NSuqsL1VJWIpTa6Rw--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/5f51a25e036ab7072a0f6a706700500b.jpg" width="130" height="86" alt="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Saeed Jalili listens to a question during a final news conference in Almaty, Kazakhstan, Wednesday, Feb. 27, 2013. Negotiations with world powers over how to curb Iran&#039;s nuclear program have reached a &quot;turning point&quot; for the better after nearly breaking down last year, the Islamic republic&#039;s top official at diplomatic talks said Wednesday at the close of two days of delicate discussions aimed at preventing Tehran from building an atomic arsenal. (AP Photo/Pavel Mikheyev)" align="left" title="Iran&#039;s Supreme National Security Council Secretary and chief nuclear negotiator Saeed Jalili listens to a question during a final news conference in Almaty, Kazakhstan, Wednesday, Feb. 27, 2013. Negotiations with world powers over how to curb Iran&#039;s nuclear program have reached a &quot;turning point&quot; for the better after nearly breaking down last year, the Islamic republic&#039;s top official at diplomatic talks said Wednesday at the close of two days of delicate discussions aimed at preventing Tehran from building an atomic arsenal. (AP Photo/Pavel Mikheyev)" border="0" /></a>ALMATY, Kazakhstan (AP) — World powers offered broader concessions than ever to Iran in attempts Wednesday to keep alive diplomatic channels that seek to rein in the Islamic Republic&#039;s nuclear program and prevent it from building an atomic weapon.</p><br clear="all"/>Loved ones salute New Zealand dad killed by shark<p><a href="http://news.yahoo.com/loved-ones-salute-zealand-dad-killed-shark-234356906.html"><img src="http://l3.yimg.com/bt/api/res/1.2/ImEAY57ljHgWT373hUgquA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/8c8c807d200ec4072a0f6a706700e493.jpg" width="130" height="86" alt="A no swimming sign is displayed at Muriwai Beach near Auckland, New Zealand, Thursday, Feb. 28, 2013, a day after Adam Strange was killed by a shark. About 150 friends and family of Strange, 46, wrote messages to him in the sand and stepped into the water Thursday at a New Zealand beach to say goodbye after he was killed Wednesday by a large shark. (AP Photo/New Zealand Herald, Brett Phibbs) New Zealand Out, Australia Out" align="left" title="A no swimming sign is displayed at Muriwai Beach near Auckland, New Zealand, Thursday, Feb. 28, 2013, a day after Adam Strange was killed by a shark. About 150 friends and family of Strange, 46, wrote messages to him in the sand and stepped into the water Thursday at a New Zealand beach to say goodbye after he was killed Wednesday by a large shark. (AP Photo/New Zealand Herald, Brett Phibbs) New Zealand Out, Australia Out" border="0" /></a>WELLINGTON, New Zealand (AP) — About 150 friends and family of a man killed in a shark attack wrote messages to him in the sand Thursday and stepped into the water at a New Zealand beach to say goodbye.</p><br clear="all"/>http://news.yahoo.com/loved-ones-salute-zealand-dad-killed-shark-234356906.htmlThu, 28 Feb 2013 02:19:09 -0500Associated Pressloved-ones-salute-zealand-dad-killed-shark-234356906<p><a href="http://news.yahoo.com/loved-ones-salute-zealand-dad-killed-shark-234356906.html"><img src="http://l3.yimg.com/bt/api/res/1.2/ImEAY57ljHgWT373hUgquA--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/8c8c807d200ec4072a0f6a706700e493.jpg" width="130" height="86" alt="A no swimming sign is displayed at Muriwai Beach near Auckland, New Zealand, Thursday, Feb. 28, 2013, a day after Adam Strange was killed by a shark. About 150 friends and family of Strange, 46, wrote messages to him in the sand and stepped into the water Thursday at a New Zealand beach to say goodbye after he was killed Wednesday by a large shark. (AP Photo/New Zealand Herald, Brett Phibbs) New Zealand Out, Australia Out" align="left" title="A no swimming sign is displayed at Muriwai Beach near Auckland, New Zealand, Thursday, Feb. 28, 2013, a day after Adam Strange was killed by a shark. About 150 friends and family of Strange, 46, wrote messages to him in the sand and stepped into the water Thursday at a New Zealand beach to say goodbye after he was killed Wednesday by a large shark. (AP Photo/New Zealand Herald, Brett Phibbs) New Zealand Out, Australia Out" border="0" /></a>WELLINGTON, New Zealand (AP) — About 150 friends and family of a man killed in a shark attack wrote messages to him in the sand Thursday and stepped into the water at a New Zealand beach to say goodbye.</p><br clear="all"/>Bradley Manning to admit partial guilt in WikiLeaks caseArmy Pvt. Bradley Manning admitted in a court filing Tuesday to leaking at least some of the classified US military and State Department documents that made Julian Assange's Wikileaks a controversial sensation three years ago, in an apparent bid to get an opportunity to explain his motives.http://news.yahoo.com/bradley-manning-admit-partial-guilt-wikileaks-case-215810045.htmlWed, 27 Feb 2013 16:58:10 -0500Christian Science Monitorbradley-manning-admit-partial-guilt-wikileaks-case-215810045For Bulgarians, brief love affair with credit comes to bitter endWhen Dobromir Kyurkchiev purchased a new home in Sofia, he took out a 45,000 euro ($58,875), 25-year loan. A real estate broker himself, he was familiar with loans and made certain the contract provided a fixed rate. About five years later, though, his monthly payment unexpectedly jumped 20 percent.http://news.yahoo.com/bulgarians-brief-love-affair-credit-comes-bitter-end-211858869.htmlWed, 27 Feb 2013 16:18:58 -0500Christian Science Monitorbulgarians-brief-love-affair-credit-comes-bitter-end-211858869Are Italian voters right that austerity isn't working?There was little doubt that austerity – and opposition to it – would play a major role in Italy's national elections, and play a role austerity did. The campaign yielded results well beyond expectations for both of the parties that campaigned heavily against austerity measures: Beppe Grillo's Five Star Movement and Silvio Berlusconi's People of Freedom.http://news.yahoo.com/italian-voters-austerity-isnt-working-211124790.htmlWed, 27 Feb 2013 16:11:24 -0500Christian Science Monitoritalian-voters-austerity-isnt-working-211124790Pistorius tragedy, characters prove a never-ending soap opera in South AfricaThe Oscar Pistorius saga continues to zig and zag through South African Twitter feeds, townships, taxi driver chat, and posh suburban clubs like some monster rogue soap opera that no one can turn off.http://news.yahoo.com/pistorius-tragedy-characters-prove-never-ending-soap-opera-210126253.htmlWed, 27 Feb 2013 16:01:26 -0500Christian Science Monitorpistorius-tragedy-characters-prove-never-ending-soap-opera-210126253Logistics unhinge Peru's laptop dreamsWhen Peru decided to invest in the One Laptop Per Child (OLPC) program in 2007, the government knew it couldn’t afford to rush out and buy a laptop for every child all at once.http://news.yahoo.com/logistics-unhinge-perus-laptop-dreams-204637645.htmlWed, 27 Feb 2013 15:46:37 -0500Christian Science Monitorlogistics-unhinge-perus-laptop-dreams-204637645Israel wields Bible's soft power as far afield as BrazilOn a crisp winter morning in Jerusalem, a group of American Christian leaders with Bibles under their arms walk the hilltop where many believe King David first established the Jewish capital some 3,000 years ago.http://news.yahoo.com/israel-wields-bibles-soft-power-far-afield-brazil-200404877.htmlWed, 27 Feb 2013 15:04:04 -0500Christian Science Monitorisrael-wields-bibles-soft-power-far-afield-brazil-200404877Criminals cash in on Syria's chaos with kidnappings and ransomsAlaa’s uncle was a prominent figure in his community and although, as a matter of self-preservation, he has not advertised his political beliefs since Syria's uprising began, he was widely known as a friend of the opposition.http://news.yahoo.com/criminals-cash-syrias-chaos-kidnappings-ransoms-192448434.htmlWed, 27 Feb 2013 14:24:48 -0500Christian Science Monitorcriminals-cash-syrias-chaos-kidnappings-ransoms-192448434Are the US and Russia bridging their divide over Syria?After a surprisingly positive first meeting between Secretary of State John Kerry and Russian Foreign Minister Sergey Lavrov in Berlin Tuesday, Russian experts say they're hopeful that a real opportunity has opened up to pressure the Bashar al-Assad regime and Syria's fractured rebel movement to come to the bargaining table and discuss a negotiated end to the stalemated civil war that has killed around 70,000 people in the past two years.http://news.yahoo.com/us-russia-bridging-divide-over-syria-162102330.htmlWed, 27 Feb 2013 11:21:02 -0500Christian Science Monitorus-russia-bridging-divide-over-syria-162102330Can Kenya's March election avoid killings, catastrophe, of last national vote?The most infamous of the many violent atrocities that followed Kenya's last election in 2007 came when 20 people perished in a church in the western village of Kiambaa, set aflame by mobs supporting a rival politician.http://news.yahoo.com/kenyas-march-election-avoid-killings-catastrophe-last-national-153437704.htmlWed, 27 Feb 2013 10:34:37 -0500Christian Science Monitorkenyas-march-election-avoid-killings-catastrophe-last-national-153437704Will Twitter make an impact in Kenya's elections next week?Social media – tweets, tags, pokes, posts, uploads – were not part of Kenya's last election. So new media can't be blamed for the violence that dented Kenya's image of stability in 2007.http://news.yahoo.com/twitter-impact-kenyas-elections-next-week-153415051.htmlWed, 27 Feb 2013 10:34:15 -0500Christian Science Monitortwitter-impact-kenyas-elections-next-week-153415051Taliban attacks in Afghanistan not down after allWas the war in Afghanistan going better in 2012 than it was in 2011?http://news.yahoo.com/taliban-attacks-afghanistan-not-down-144015063.htmlWed, 27 Feb 2013 09:40:15 -0500Christian Science Monitortaliban-attacks-afghanistan-not-down-144015063Sugar Man: Did the Oscar-winning documentary mislead viewers?With the world’s gaze still trained on Oscar Pistorius – the Olympian runner who shot and killed his girlfriend on Valentines Day – it’s been something of a rough news week for South Africa.http://news.yahoo.com/sugar-man-did-oscar-winning-documentary-mislead-viewers-140006899.htmlWed, 27 Feb 2013 09:00:06 -0500Christian Science Monitorsugar-man-did-oscar-winning-documentary-mislead-viewers-140006899Can Dennis Rodman's 'basketball diplomacy' make a difference in North Korea?Dennis Rodman, famous for his rebounding on the court and his flamboyant, quirky persona off it, is not the typical cultural attache for the US. But that's the role he's playing this week in North Korea.http://news.yahoo.com/dennis-rodmans-basketball-diplomacy-difference-north-korea-134848310.htmlWed, 27 Feb 2013 08:48:48 -0500Christian Science Monitordennis-rodmans-basketball-diplomacy-difference-north-korea-134848310Egypt opposition vows to boycott parliamentary electionsEgypt's main opposition coalition announced today it will boycott upcoming parliamentary elections, deepening the political crisis in Egypt and practically ensuring that Egypt's next legislative body will be dominated by Islamists.http://news.yahoo.com/egypt-opposition-vows-boycott-parliamentary-elections-210104465.htmlTue, 26 Feb 2013 16:01:04 -0500Christian Science Monitoregypt-opposition-vows-boycott-parliamentary-elections-210104465Is a third Palestinian intifada coming?The status quo between Israelis and Palestinians is, as is so frequently uttered, "intolerable." But rhetorically intolerable things are often tolerated for long periods of time.http://news.yahoo.com/third-palestinian-intifada-coming-204213355.htmlTue, 26 Feb 2013 15:42:13 -0500Christian Science Monitorthird-palestinian-intifada-coming-204213355No laughing matter: How a comedian's election is upending ItalyItalian politics has long been the butt of jokes, with its revolving-door governments and larger-than-life personalities like the scandal-prone Silvio Berlusconi.http://news.yahoo.com/no-laughing-matter-comedians-election-upending-italy-202440542.htmlTue, 26 Feb 2013 15:24:40 -0500Christian Science Monitorno-laughing-matter-comedians-election-upending-italy-202440542Inflation plays role in Argentine teacher strikeFollowing a demand this month from the International Monetary Fund to improve her government's data, Argentinian President Cristina Fernández de Kirchner’s refusal to acknowledge the soaring inflation rate has now led to a strike by teachers unions – and all this in an election year.http://news.yahoo.com/inflation-plays-role-argentine-teacher-strike-202051043.htmlTue, 26 Feb 2013 15:20:51 -0500Christian Science Monitorinflation-plays-role-argentine-teacher-strike-202051043Heroes to Heroes helps wounded US vets recoverHe’d suffered from nightmares and had used alcohol to blot out depression. After leaving Iraq as a wounded soldier in 2004, Harrison Manyoma of Humble, Texas, remained haunted by his experiences, which had culminated in a roadside car bomb explosion.http://news.yahoo.com/heroes-heroes-helps-wounded-us-vets-recover-193102506.htmlTue, 26 Feb 2013 14:31:02 -0500Christian Science Monitorheroes-heroes-helps-wounded-us-vets-recover-193102506Italian political deadlock casts new uncertainty on eurozone recoveryEurope’s murky path to recovery was rattled yet again Tuesday as markets and policymakers tried to digest the unexpected Italian electoral results and the consequences, especially on periphery economies.http://news.yahoo.com/italian-political-deadlock-casts-uncertainty-eurozone-recovery-175129762.htmlTue, 26 Feb 2013 12:51:29 -0500Christian Science Monitoritalian-political-deadlock-casts-uncertainty-eurozone-recovery-175129762Amid Palestinian protests, Gaza militants fire rocket into Israel<p><a href="http://news.yahoo.com/amid-palestinian-protests-gaza-militants-fire-rocket-israel-135849287.html"><img src="http://l.yimg.com/bt/api/res/1.2/BOmPub6xs1wfp9ydSbMk8w--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/da1f9b30c5ee88062a0f6a706700a215.jpg" width="130" height="86" alt="Israeli security forces take positions during clashes after the funeral of Arafat Jaradat in the West Bank of Hebron, Monday, Feb. 25, 2013. Thousands have attended the funeral procession of a 30-year-old Palestinian man who died under disputed circumstances in Israeli custody. Palestinian officials say autopsy results show Jaradat was tortured by Israeli interrogators, while Israeli officials say there&#039;s no conclusive cause of death yet and that more tests are needed.(AP Photo/Nasser Shiyoukhi)" align="left" title="Israeli security forces take positions during clashes after the funeral of Arafat Jaradat in the West Bank of Hebron, Monday, Feb. 25, 2013. Thousands have attended the funeral procession of a 30-year-old Palestinian man who died under disputed circumstances in Israeli custody. Palestinian officials say autopsy results show Jaradat was tortured by Israeli interrogators, while Israeli officials say there&#039;s no conclusive cause of death yet and that more tests are needed.(AP Photo/Nasser Shiyoukhi)" border="0" /></a>• A daily summary of global reports on security issues.</p><br clear="all"/>http://news.yahoo.com/amid-palestinian-protests-gaza-militants-fire-rocket-israel-135849287.htmlTue, 26 Feb 2013 08:58:49 -0500Christian Science Monitoramid-palestinian-protests-gaza-militants-fire-rocket-israel-135849287<p><a href="http://news.yahoo.com/amid-palestinian-protests-gaza-militants-fire-rocket-israel-135849287.html"><img src="http://l.yimg.com/bt/api/res/1.2/BOmPub6xs1wfp9ydSbMk8w--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/da1f9b30c5ee88062a0f6a706700a215.jpg" width="130" height="86" alt="Israeli security forces take positions during clashes after the funeral of Arafat Jaradat in the West Bank of Hebron, Monday, Feb. 25, 2013. Thousands have attended the funeral procession of a 30-year-old Palestinian man who died under disputed circumstances in Israeli custody. Palestinian officials say autopsy results show Jaradat was tortured by Israeli interrogators, while Israeli officials say there&#039;s no conclusive cause of death yet and that more tests are needed.(AP Photo/Nasser Shiyoukhi)" align="left" title="Israeli security forces take positions during clashes after the funeral of Arafat Jaradat in the West Bank of Hebron, Monday, Feb. 25, 2013. Thousands have attended the funeral procession of a 30-year-old Palestinian man who died under disputed circumstances in Israeli custody. Palestinian officials say autopsy results show Jaradat was tortured by Israeli interrogators, while Israeli officials say there&#039;s no conclusive cause of death yet and that more tests are needed.(AP Photo/Nasser Shiyoukhi)" border="0" /></a>• A daily summary of global reports on security issues.</p><br clear="all"/> + + From 249fc01b911a00783a8275524acab67070566b39 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 28 Feb 2013 09:08:13 +0100 Subject: [PATCH 0630/1590] Small test speedup (2-3sec) by not going through the admin all the time Refs #313. --- tests/testapp/tests/page_tests.py | 134 ++++++++++++++++++------------ 1 file changed, 82 insertions(+), 52 deletions(-) diff --git a/tests/testapp/tests/page_tests.py b/tests/testapp/tests/page_tests.py index d70a05c1c..6358f4e37 100644 --- a/tests/testapp/tests/page_tests.py +++ b/tests/testapp/tests/page_tests.py @@ -70,7 +70,7 @@ def setUp(self): def login(self): self.assertTrue(self.client.login(username='test', password='test')) - def create_page(self, title='Test page', parent='', **kwargs): + def create_page_through_admin(self, title='Test page', parent='', **kwargs): dic = { 'title': title, 'slug': kwargs.get('slug', slugify(title)), @@ -110,10 +110,30 @@ def create_page(self, title='Test page', parent='', **kwargs): dic.update(kwargs) return self.client.post('/admin/page/page/add/', dic) - def create_default_page_set(self): + def create_default_page_set_through_admin(self): self.login() - self.create_page() - return self.create_page('Test child page', 1) + self.create_page_through_admin() + return self.create_page_through_admin('Test child page', 1) + + def create_page(self, title='Test page', parent=None, **kwargs): + defaults = { + 'template_key': 'base', + 'site': self.site_1, + 'in_navigation': False, + 'active': False, + } + defaults.update(kwargs) + return Page.objects.create( + title=title, + slug=kwargs.get('slug', slugify(title)), + parent=parent, + **defaults) + + def create_default_page_set(self): + self.create_page( + 'Test child page', + parent=self.create_page(), + ) def is_published(self, url, should_be=True): try: @@ -135,23 +155,23 @@ def test_01_tree_editor(self): def test_02_add_page(self): self.login() - self.assertRedirects(self.create_page(title='Test page ' * 10, slug='test-page'), + self.assertRedirects(self.create_page_through_admin(title='Test page ' * 10, slug='test-page'), '/admin/page/page/') self.assertEqual(Page.objects.count(), 1) self.assertContains(self.client.get('/admin/page/page/'), u'…') def test_03_item_editor(self): self.login() - self.assertRedirects(self.create_page(_continue=1), '/admin/page/page/1/') + self.assertRedirects(self.create_page_through_admin(_continue=1), '/admin/page/page/1/') self.assertEqual(self.client.get('/admin/page/page/1/').status_code, 200) self.is_published('/admin/page/page/42/', should_be=False) def test_03_add_another(self): self.login() - self.assertRedirects(self.create_page(_addanother=1), '/admin/page/page/add/') + self.assertRedirects(self.create_page_through_admin(_addanother=1), '/admin/page/page/add/') def test_04_add_child(self): - response = self.create_default_page_set() + response = self.create_default_page_set_through_admin() self.assertRedirects(response, '/admin/page/page/') self.assertEqual(Page.objects.count(), 2) @@ -207,6 +227,7 @@ def test_06_tree_editor_save(self): self.assertEqual(page4.get_absolute_url(), '/test-page/page4/') self.assertEqual(page5.get_absolute_url(), '/page5/') + self.login() self.client.post('/admin/page/page/', { '__cmd': 'move_node', 'position': 'last-child', @@ -226,6 +247,7 @@ def test_07_tree_editor_toggle_boolean(self): self.assertEqual(Page.objects.get(pk=1).in_navigation, False) + self.login() self.assertContains(self.client.post('/admin/page/page/', { '__cmd': 'toggle_boolean', 'item_id': 1, @@ -291,7 +313,7 @@ def test_08_publishing(self): self.is_published(page.get_absolute_url(), should_be=True) self.is_published(page2.get_absolute_url(), should_be=True) - def create_pagecontent(self, page, **kwargs): + def create_page_through_admincontent(self, page, **kwargs): data = { 'title': page.title, 'slug': page.slug, @@ -347,7 +369,8 @@ def test_09_pagecontent(self): self.create_default_page_set() page = Page.objects.get(pk=1) - response = self.create_pagecontent(page) + self.login() + response = self.create_page_through_admincontent(page) self.assertRedirects(response, '/admin/page/page/') self.assertEqual(page.content.main[0].__class__.__name__, 'RawContent') @@ -374,9 +397,10 @@ def test_09_pagecontent(self): def test_10_mediafile_and_imagecontent(self): self.create_default_page_set() + self.login() page = Page.objects.get(pk=1) - self.create_pagecontent(page) + self.create_page_through_admincontent(page) category = Category.objects.create(title='Category', parent=None) category2 = Category.objects.create(title='Something', parent=category) @@ -575,7 +599,8 @@ def test_14_richtext(self): def test_15_frontend_editing(self): self.create_default_page_set() page = Page.objects.get(pk=1) - self.create_pagecontent(page) + self.login() + self.create_page_through_admincontent(page) # this should return a 404 self.is_published('/admin/page/page/10|rawcontent|1/', should_be=False) @@ -598,7 +623,8 @@ def test_15_frontend_editing(self): def test_15_b_client_frontend_editing(self): self.create_default_page_set() page = Page.objects.get(pk=1) - self.create_pagecontent(page) + self.login() + self.create_page_through_admincontent(page) page.active = True page.template_key = 'theother' @@ -641,11 +667,6 @@ def test_15_b_client_frontend_editing(self): # cleanup request processor del Page.request_processors['frontend_editing'] - def test_16_template_tags(self): - # Directly testing template tags doesn't make any sense since - # feincms_render_* do not use simple_tag anymore - pass - def test_17_page_template_tags(self): self.create_default_page_set() @@ -744,30 +765,30 @@ def test_17_feincms_nav(self): self.login() - self.create_page('Page 1') # 1 - self.create_page('Page 1.1', 1) - self.create_page('Page 1.2', 1) # 3 - self.create_page('Page 1.2.1', 3) - self.create_page('Page 1.2.2', 3) - self.create_page('Page 1.2.3', 3) - self.create_page('Page 1.3', 1) - - self.create_page('Page 2') # 8 - self.create_page('Page 2.1', 8) - self.create_page('Page 2.2', 8) - self.create_page('Page 2.3', 8) - - self.create_page('Page 3') # 12 - self.create_page('Page 3.1', 12) - self.create_page('Page 3.2', 12) - self.create_page('Page 3.3', 12) # 15 - self.create_page('Page 3.3.1', 15) # 16 - self.create_page('Page 3.3.1.1', 16) - self.create_page('Page 3.3.2', 15) - - self.create_page('Page 4') # 19 - self.create_page('Page 4.1', 19) - self.create_page('Page 4.2', 19) + self.create_page_through_admin('Page 1') # 1 + self.create_page_through_admin('Page 1.1', 1) + self.create_page_through_admin('Page 1.2', 1) # 3 + self.create_page_through_admin('Page 1.2.1', 3) + self.create_page_through_admin('Page 1.2.2', 3) + self.create_page_through_admin('Page 1.2.3', 3) + self.create_page_through_admin('Page 1.3', 1) + + self.create_page_through_admin('Page 2') # 8 + self.create_page_through_admin('Page 2.1', 8) + self.create_page_through_admin('Page 2.2', 8) + self.create_page_through_admin('Page 2.3', 8) + + self.create_page_through_admin('Page 3') # 12 + self.create_page_through_admin('Page 3.1', 12) + self.create_page_through_admin('Page 3.2', 12) + self.create_page_through_admin('Page 3.3', 12) # 15 + self.create_page_through_admin('Page 3.3.1', 15) # 16 + self.create_page_through_admin('Page 3.3.1.1', 16) + self.create_page_through_admin('Page 3.3.2', 15) + + self.create_page_through_admin('Page 4') # 19 + self.create_page_through_admin('Page 4.1', 19) + self.create_page_through_admin('Page 4.2', 19) """ Creates the following structure: @@ -986,7 +1007,8 @@ def test_20_redirects(self): def test_21_copy_content(self): self.create_default_page_set() page = Page.objects.get(pk=1) - self.create_pagecontent(page) + self.login() + self.create_page_through_admincontent(page) page2 = Page.objects.get(pk=2) page2.copy_content_from(page) @@ -1049,15 +1071,16 @@ def test_23_navigation_extension(self): def test_24_admin_redirects(self): self.create_default_page_set() + self.login() page = Page.objects.get(pk=1) - response = self.create_pagecontent(page, _continue=1) + response = self.create_page_through_admincontent(page, _continue=1) self.assertRedirects(response, '/admin/page/page/1/') - response = self.create_pagecontent(page, _addanother=1) + response = self.create_page_through_admincontent(page, _addanother=1) self.assertRedirects(response, '/admin/page/page/add/') - response = self.create_pagecontent(page) + response = self.create_page_through_admincontent(page) self.assertRedirects(response, '/admin/page/page/') def test_25_applicationcontent(self): @@ -1155,11 +1178,13 @@ def test_25_applicationcontent(self): self.assertEqual(app_reverse('ac_module_root', 'whatever'), '/test-page/') # Ensure ApplicationContent's admin_fields support works properly + self.login() self.assertContains(self.client.get('/admin/page/page/%d/' % page.id), 'exclusive_subpages') def test_26_page_form_initial(self): self.create_default_page_set() + self.login() self.assertEqual(self.client.get('/admin/page/page/add/?translation_of=1&lang=de').status_code, 200) self.assertEqual(self.client.get('/admin/page/page/add/?parent=1').status_code, 200) @@ -1175,7 +1200,8 @@ def test_27_cached_url_clash(self): page1.active = True page1.save() - self.assertContains(self.create_pagecontent(page2, active=True, override_url='/'), + self.login() + self.assertContains(self.create_page_through_admincontent(page2, active=True, override_url='/'), 'already taken by') def test_28_applicationcontent_reverse(self): @@ -1200,9 +1226,10 @@ def test_28_applicationcontent_reverse(self): # when specific applicationcontent exists more then once reverse should return url # for the one that has tree_id same as current feincms page - self.create_page(title='Home DE', language='de', active=True) + self.login() + self.create_page_through_admin(title='Home DE', language='de', active=True) page_de = Page.objects.get(title='Home DE') - self.create_page(title='Child 1 DE', language='de', parent=page_de.id, active=True) + self.create_page_through_admin(title='Child 1 DE', language='de', parent=page_de.id, active=True) page_de_1 = Page.objects.get(title='Child 1 DE') page_de_1.applicationcontent_set.create( region='main', ordering=0, @@ -1220,6 +1247,7 @@ def test_28_applicationcontent_reverse(self): def test_29_medialibrary_admin(self): self.create_default_page_set() + self.login() page = Page.objects.get(pk=1) @@ -1279,8 +1307,8 @@ def test_30_context_processors(self): def test_31_sites_framework_associating_with_single_site(self): self.login() site_2 = Site.objects.create(name='site 2', domain='2.example.com') - self.create_page('site 1 homepage', override_url='/', active=True) - self.create_page('site 2 homepage', override_url='/', + self.create_page_through_admin('site 1 homepage', override_url='/', active=True) + self.create_page_through_admin('site 2 homepage', override_url='/', site=site_2.id, active=True) self.assertEqual(Page.objects.count(), 2) self.assertEqual(Page.objects.active().count(), 1) @@ -1329,6 +1357,7 @@ def test_33_preview(self): ordering=0, text='Example content') + self.login() self.assertEquals(self.client.get(page.get_absolute_url()).status_code, 404) self.assertContains(self.client.get('%s_preview/%s/' % (page.get_absolute_url(), page.pk)), 'Example content') @@ -1342,7 +1371,8 @@ def test_34_access(self): Page.objects.update(active=True) - self.create_page(title='redirect page', override_url='/', redirect_to=page.get_absolute_url(), active=True) + self.login() + self.create_page_through_admin(title='redirect page', override_url='/', redirect_to=page.get_absolute_url(), active=True) # / -> redirect to /something/ r = self.client.get('/') From a4377da41c3d067f28693688b42163a3ea911d9e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 28 Feb 2013 10:04:21 +0100 Subject: [PATCH 0631/1590] Fix sitemap generation when there are no pages yet Thanks to javisto for the report. Fixes #393. --- feincms/module/page/sitemap.py | 2 +- feincms/tests/page_tests.py | 14 ++++++++++++++ tests/testapp/settings.py | 1 + tests/testapp/urls.py | 7 +++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index bda5f2b16..8a418c9f1 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -52,7 +52,7 @@ def items(self): if callable(base_qs): base_qs = base_qs() - self.max_depth = base_qs.aggregate(Max('level'))['level__max'] + self.max_depth = base_qs.aggregate(Max('level'))['level__max'] or 0 if self.depth_cutoff > 0: self.max_depth = min(self.depth_cutoff, self.max_depth) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 076dc584c..4a6187001 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -1392,3 +1392,17 @@ def test_35_access_with_extra_path(self): self.assertEquals(r.status_code, 404) feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old + + def test_36_sitemaps(self): + response = self.client.get('/sitemap.xml') + self.assertContains(response, '', status_code=200) + + page.active = True + page.in_navigation = True + page.save() + response = self.client.get('/sitemap.xml') + self.assertContains(response, '', status_code=200) diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 2b5fd39e0..b15faf686 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -14,6 +14,7 @@ 'django.contrib.admin', 'django.contrib.contenttypes', 'django.contrib.sessions', + 'django.contrib.sitemaps', 'django.contrib.sites', 'django.contrib.staticfiles', 'feincms', diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index e8ef39876..2e9d27ee5 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -4,6 +4,10 @@ from django.contrib import admin from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from feincms.module.page.sitemap import PageSitemap + + +sitemaps = {'pages' : PageSitemap} admin.autodiscover() @@ -13,6 +17,9 @@ url(r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': os.path.join(os.path.dirname(__file__), 'media/')}), + url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', + {'sitemaps': sitemaps}), + url(r'', include('feincms.contrib.preview.urls')), url(r'', include('feincms.views.cbv.urls')), ) From 0377b641988f3e44a22e3f051458115c7a86526d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 1 Mar 2013 15:18:39 +0100 Subject: [PATCH 0632/1590] Fix #394: Generation of extension search paths Thanks to Alen Mujezinovic for the report. --- feincms/extensions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 0af2a5b56..4d1131392 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -51,8 +51,12 @@ def register_extensions(cls, *extensions): extension = None if isinstance(ext, basestring): - paths = [ext, '%s.register' % ext] + [ - '%s.%s.register' % (path, ext) for path in search_paths] + paths = [ext, '%s.register' % ext] + for path in search_paths: + paths.extend([ + '%s.%s.register' % (path, ext), + '%s.%s' % (path, ext), + ]) for idx, path in enumerate(paths): try: From 13ba46e8084bc4d1880190263ef0b9c467f93c72 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 1 Mar 2013 15:19:12 +0100 Subject: [PATCH 0633/1590] FeinCMS v1.7.1 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 65dbe3019..13ba6bf8f 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 7, 0) +VERSION = (1, 7, 1) __version__ = '.'.join(map(str, VERSION)) From 71e168a8e15886a1affb3e4b796a59b127d1cbc7 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 6 Mar 2013 11:11:48 +0100 Subject: [PATCH 0634/1590] Use modern import for django.conf.urls --- docs/integration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integration.rst b/docs/integration.rst index 96ab32bb3..b0f5f1ca2 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -245,7 +245,7 @@ of any template rendering calls: ``urls.py``:: - from django.conf.urls.defaults import patterns, include, url + from django.conf.urls import patterns, include, url urlpatterns = patterns('news.views', url(r'^$', 'entry_list', name='entry_list'), From 8968059a544fa1c27111b93b479343d749ca495c Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Mon, 11 Mar 2013 21:46:10 +1100 Subject: [PATCH 0635/1590] POSITION_CHOICES not mandatory since 3e391fd0 --- docs/contenttypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index bbef78696..b8048dbb4 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -348,7 +348,7 @@ position. You should probably use the MediaFileContent though. Additional arguments for :func:`~feincms.models.Base.create_content_type`: -* ``POSITION_CHOICES`` (mandatory) +* ``POSITION_CHOICES`` * ``FORMAT_CHOICES`` From 5a2d6480df81fd49ad3be0b6e41e983452c3a69d Mon Sep 17 00:00:00 2001 From: Greg Turner Date: Wed, 13 Mar 2013 11:09:26 +1100 Subject: [PATCH 0636/1590] Re #323 - models cache is cleared at the end of ensure_completely_loaded, so as to play nice with Django 1.5. --- feincms/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/feincms/__init__.py b/feincms/__init__.py index 7fb46bea6..5fb45b2ba 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -58,5 +58,15 @@ def ensure_completely_loaded(force=False): except AttributeError: pass + # Calls to get_models(...) are cached by the arguments used in the call. + # This cache is normally cleared in loading.register_models(), but we + # somehow (how?) invalidate the get_models() cache, perhaps by calling it + # 'prematurely' above. So we clear the get_models cache again here. If we + # don't do this, Django 1.5 chokes on a model validation error (Django 1.4 + # doesn't exhibit this problem). See Issue #323 on github. + # Current best guess at a root cause is changed model registration procedure + # in Django 1.5 due to swappable models. + loading.cache._get_models_cache.clear() + COMPLETELY_LOADED = True return True From 149954ccc393a9dd3ec116082ff95e960d1646da Mon Sep 17 00:00:00 2001 From: Greg Turner Date: Wed, 13 Mar 2013 11:35:13 +1100 Subject: [PATCH 0637/1590] Better explanation re #323. --- feincms/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 5fb45b2ba..faea902bf 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -60,12 +60,12 @@ def ensure_completely_loaded(force=False): # Calls to get_models(...) are cached by the arguments used in the call. # This cache is normally cleared in loading.register_models(), but we - # somehow (how?) invalidate the get_models() cache, perhaps by calling it - # 'prematurely' above. So we clear the get_models cache again here. If we - # don't do this, Django 1.5 chokes on a model validation error (Django 1.4 - # doesn't exhibit this problem). See Issue #323 on github. - # Current best guess at a root cause is changed model registration procedure - # in Django 1.5 due to swappable models. + # invalidate the get_models() cache, by calling get_models + # above before all apps have loaded. (Django's load_app() doesn't clear the + # get_models cache as it perhaps should). So instead we clear the + # get_models cache again here. If we don't do this, Django 1.5 chokes on + # a model validation error (Django 1.4 doesn't exhibit this problem). + # See Issue #323 on github. loading.cache._get_models_cache.clear() COMPLETELY_LOADED = True From 75cd6b2d37220abcf659e9e2779ec81cbd6d1eae Mon Sep 17 00:00:00 2001 From: Greg Turner Date: Wed, 13 Mar 2013 17:10:40 +1100 Subject: [PATCH 0638/1590] Re #399 catches "%sContent" class name conflicts and produces a warning. --- feincms/models.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 844a0bc2e..e94effb55 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -5,6 +5,7 @@ the feincms\_ namespace. """ +import sys import operator import warnings @@ -510,8 +511,18 @@ def get_queryset(cls, filter_args): } # create content base type and save reference on CMS class - cls._feincms_content_model = type('%sContent' % cls.__name__, - (models.Model,), attrs) + + name = '%sContent' % cls.__name__ + if hasattr(sys.modules[cls.__module__], name): + warnings.warn( + 'The class %s.%s has the same name as the class that ' + 'FeinCMS auto-generates based on %s.%s. To avoid database' + 'errors and import clashes, rename one of these classes.' + % (cls.__module__, name, cls.__module__, cls.__name__), + RuntimeWarning) + + cls._feincms_content_model = type(name, (models.Model,), attrs) + # list of concrete content types cls._feincms_content_types = [] From a365e3a295ef9f6f29c9038ab2bc106b48516af9 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 13 Mar 2013 20:26:58 +0100 Subject: [PATCH 0639/1590] Pages in navigation are more rare than not, so make the default in_navigation False. --- feincms/module/page/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 4b4d3339d..47adae1d0 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -163,7 +163,7 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): slug = models.SlugField(_('slug'), max_length=150) parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, null=True, related_name='children') parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py - in_navigation = models.BooleanField(_('in navigation'), default=True) + in_navigation = models.BooleanField(_('in navigation'), default=False) override_url = models.CharField(_('override URL'), max_length=255, blank=True, help_text=_('Override the target URL. Be sure to include slashes at the beginning and at the end if it is a local URL. This affects both the navigation and subpages\' URLs.')) redirect_to = models.CharField(_('redirect to'), max_length=255, blank=True, From 1f8ce957a5bf0d5673faa098f98785ca4b07a301 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 14 Mar 2013 11:57:00 +0100 Subject: [PATCH 0640/1590] Tests: Do not register_regions in setup(), avoid "RuntimeWarning: Ignoring second call to register_regions" --- tests/testapp/models.py | 4 +--- tests/testapp/tests/tests.py | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 502bf7355..db64f1273 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -47,10 +47,8 @@ def get_admin_fields(form, *args, **kwargs): ('whatever', 'Test Urls', {'urls': 'testapp.applicationcontent_urls'}), )) +Entry.register_regions(('main', 'Main region'), ('another', 'Another region')) -Entry.register_regions( - ('main', 'Main region'), - ) Entry.create_content_type(RawContent) Entry.create_content_type(ImageContent, POSITION_CHOICES=( ('default', 'Default position'), diff --git a/tests/testapp/tests/tests.py b/tests/testapp/tests/tests.py index fd9d86ba1..57a77bfbe 100644 --- a/tests/testapp/tests/tests.py +++ b/tests/testapp/tests/tests.py @@ -102,8 +102,6 @@ def setUp(self): u.set_password('test') u.save() - Entry.register_regions(('main', 'Main region'), ('another', 'Another region')) - def login(self): self.assertTrue(self.client.login(username='test', password='test')) From b3aff07623a605bd9dca66e57813ea2270823ec5 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 14 Mar 2013 12:12:49 +0100 Subject: [PATCH 0641/1590] Tests: We use the translation extensions, so add LocaleMiddleware to MIDDLEWARE_CLASSES. Avoids warning "feincms.module.extensions.translations:Could not access request.LANGUAGE_CODE" --- tests/testapp/settings.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index b15faf686..d4e455077 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -42,3 +42,12 @@ 'django.core.context_processors.static', 'django.core.context_processors.request', # request context processor is needed ) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.locale.LocaleMiddleware' +) From 5b002e18ef42365ded82e94ac3ad4500b69abdfa Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 14 Mar 2013 13:23:13 +0100 Subject: [PATCH 0642/1590] Tests: Also call module.medialibrary doctests --- tests/testapp/tests/tests.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/testapp/tests/tests.py b/tests/testapp/tests/tests.py index 57a77bfbe..0513c9579 100644 --- a/tests/testapp/tests/tests.py +++ b/tests/testapp/tests/tests.py @@ -2,9 +2,13 @@ # coding=utf-8 # ------------------------------------------------------------------------ +import doctest + from django.contrib.auth.models import User from django.test import TestCase +import feincms + from feincms.content.contactform.models import ContactFormContent, ContactForm from feincms.content.file.models import FileContent @@ -22,16 +26,12 @@ class Empty(object): pass -class TranslationsTest(TestCase): - def test_short_language_code(self): - # this is quite stupid, but it's the first time I do something - # with TestCase - - import feincms.translations - import doctest - +class DocTest(TestCase): + def test_translation_short_language_code(self): doctest.testmod(feincms.translations) + def test_medialibrary_doctests(self): + doctest.testmod(feincms.module.medialibrary.models) class ModelsTest(TestCase): def test_region(self): @@ -59,7 +59,6 @@ def test_collect_dict_values(self): self.assertEqual({'a': [1, 2], 'b': [3]}, collect_dict_values([('a', 1), ('a', 2), ('b', 3)])) - class ExampleCMSBase(Base): pass From 382d3529436ccfcecdf9a90bf974a24eb1921f1d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 14 Mar 2013 13:25:11 +0100 Subject: [PATCH 0643/1590] Rename the _feincms_content_model class to prevent name clashes Fixes #399. --- feincms/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index e94effb55..b59628d45 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -512,7 +512,7 @@ def get_queryset(cls, filter_args): # create content base type and save reference on CMS class - name = '%sContent' % cls.__name__ + name = '_Internal%sContentTypeBase' % cls.__name__ if hasattr(sys.modules[cls.__module__], name): warnings.warn( 'The class %s.%s has the same name as the class that ' From adab98ae5fde78b339167849190a3b2934f484b5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 14 Mar 2013 13:28:48 +0100 Subject: [PATCH 0644/1590] Fix test_36_sitemaps --- feincms/tests/page_tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/tests/page_tests.py b/feincms/tests/page_tests.py index 4a6187001..1aa7e80be 100644 --- a/feincms/tests/page_tests.py +++ b/feincms/tests/page_tests.py @@ -1397,10 +1397,12 @@ def test_36_sitemaps(self): response = self.client.get('/sitemap.xml') self.assertContains(response, '', status_code=200) + page = Page.objects.get() page.active = True page.in_navigation = True page.save() From 60a91c44678105706a7a95fb6d20a79fc0331196 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 14 Mar 2013 13:28:59 +0100 Subject: [PATCH 0645/1590] FeinCMS v1.7.2 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index b1ea25799..4d0561799 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 7, 1) +VERSION = (1, 7, 2) __version__ = '.'.join(map(str, VERSION)) From b4cb424b0fd6a7f82286160e50f2dbd7d64a0f68 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 15 Mar 2013 13:49:53 +0100 Subject: [PATCH 0646/1590] Fix ckeditor init template. While there, fix trailing commas in javascript arrays, IE absolutely hates them. Contributed in #389 by Hedde. --- feincms/templates/admin/content/richtext/init_ckeditor.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/templates/admin/content/richtext/init_ckeditor.html b/feincms/templates/admin/content/richtext/init_ckeditor.html index 32454a8d3..1c30cc2b9 100644 --- a/feincms/templates/admin/content/richtext/init_ckeditor.html +++ b/feincms/templates/admin/content/richtext/init_ckeditor.html @@ -2,15 +2,15 @@ - - - +{% include "admin/feincms/load-jquery.include" %} + {% include "admin/feincms/_messages_js.html" %} diff --git a/feincms/templates/admin/feincms/fe_editor_done.html b/feincms/templates/admin/feincms/fe_editor_done.html index af6cf1868..f456048e1 100644 --- a/feincms/templates/admin/feincms/fe_editor_done.html +++ b/feincms/templates/admin/feincms/fe_editor_done.html @@ -1,14 +1,4 @@ - - - +{% include "admin/feincms/load-jquery.include" %}
{{ content|safe }} diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index bcccf0387..d21458a3c 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -3,21 +3,10 @@ {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} - - +{% include "admin/feincms/load-jquery.include" %} {% endblock %} - - {% include "admin/feincms/_messages_js.html" %} diff --git a/feincms/templates/admin/feincms/load-jquery.include b/feincms/templates/admin/feincms/load-jquery.include new file mode 100644 index 000000000..9926abfa8 --- /dev/null +++ b/feincms/templates/admin/feincms/load-jquery.include @@ -0,0 +1,18 @@ +{% comment %} +Include jquery, override this template if you want to use a cdn version +or load more plugins or whatnot +{% endcomment %} + + + + + + diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index 997be2b3d..ab8a160a1 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -6,18 +6,11 @@ - - +{% include "admin/feincms/load-jquery.include" %} + From 84e711ac8b6b6d0c0c04b49427211605d4098000 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Sun, 18 Aug 2013 14:16:40 +0200 Subject: [PATCH 0725/1590] Add init_tinymce4 for tinymce 4.x (WIP) --- .../admin/content/richtext/init_tinymce4.html | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 feincms/templates/admin/content/richtext/init_tinymce4.html diff --git a/feincms/templates/admin/content/richtext/init_tinymce4.html b/feincms/templates/admin/content/richtext/init_tinymce4.html new file mode 100644 index 000000000..afdf0e660 --- /dev/null +++ b/feincms/templates/admin/content/richtext/init_tinymce4.html @@ -0,0 +1,77 @@ +{% block tinymce_script %} + {% if TINYMCE_JS_URL %} + + {% endif %} +{% endblock %} + +{% block tinymce_init %} + +{% endblock %} From 158dddf9dd030bd60d813ef3f563503d45f1d932 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 19 Aug 2013 13:15:34 +0200 Subject: [PATCH 0726/1590] Clean up init file for tinymce4. --- .../admin/content/richtext/init_tinymce4.html | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/feincms/templates/admin/content/richtext/init_tinymce4.html b/feincms/templates/admin/content/richtext/init_tinymce4.html index afdf0e660..ca18de6c7 100644 --- a/feincms/templates/admin/content/richtext/init_tinymce4.html +++ b/feincms/templates/admin/content/richtext/init_tinymce4.html @@ -26,27 +26,15 @@ function feincms_richtext_add_tinymce(field) { var tinymce_options = { {% block settings %} - theme: "advanced", - language: "en", - theme_advanced_toolbar_location: "top", - theme_advanced_toolbar_align: "left", - theme_advanced_statusbar_location: "bottom", - theme_advanced_buttons1: "{% block buttons1 %}fullscreen,|,formatselect,|,bold,italic,|,sub,sup,|,bullist,numlist,|,anchor,link,unlink,|,code{% endblock %}", - theme_advanced_buttons2: "{% block buttons2 %}{% endblock %}", - theme_advanced_buttons3: "{% block buttons3 %}{% endblock %}", - theme_advanced_path: false, - theme_advanced_blockformats: "{% block blockformats %}p,h2,h3{% endblock %}", - theme_advanced_resizing: true, - width: '680', - height: '300', - {% if TINYMCE_CONTENT_CSS_URL %}content_css: "{{ TINYMCE_CONTENT_CSS_URL }}",{% endif %} - {% if TINYMCE_LINK_LIST_URL %}external_link_list_url: "{{ TINYMCE_LINK_LIST_URL }}",{% endif %} - {% if TINYMCE_INIT_INSTANCE_CALLBACK %}init_instance_callback: "{{TINYMCE_INIT_INSTANCE_CALLBACK}}",{% endif %} - plugins: "{% block plugins %}fullscreen,paste{% endblock %}", - paste_auto_cleanup_on_paste: true, - relative_urls: false + height: '300', + {% if TINYMCE_CONTENT_CSS_URL %}content_css: "{{ TINYMCE_CONTENT_CSS_URL }}",{% endif %} + {% if TINYMCE_LINK_LIST_URL %}link_list: "{{ TINYMCE_LINK_LIST_URL }}",{% endif %} + plugins: "{% block plugins %}fullscreen paste link{% endblock %}", + paste_auto_cleanup_on_paste: true, + relative_urls: false, + invalid_elements: 'script', + statusbar: false {% endblock %} - }; var id = field ? field.id : this.id; From 58f64db2823e6271128f4d19165e29310d9e31d4 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 19 Aug 2013 13:59:51 +0200 Subject: [PATCH 0727/1590] Run tests with Django 1.4.2, as newer django-mptt requires that --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a188143c..510d5d706 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,11 @@ python: - "2.7" - "2.6" env: - - DJANGO_VERSION=1.4.0 + - DJANGO_VERSION=1.4.2 - DJANGO_VERSION=1.5.0 # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q Django==$DJANGO_VERSION django-mptt Pillow feedparser --use-mirrors - python setup.py -q install # command to run tests, e.g. python setup.py test -script: "cd tests && ./manage.py test testapp" \ No newline at end of file +script: "cd tests && ./manage.py test testapp" From 16fb4fe8614783ba81b7f874871b0174e035a0e6 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 19 Aug 2013 14:04:39 +0200 Subject: [PATCH 0728/1590] Codify req on django >= 1.4.2 for django-mptt requiring that --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ecbf9c410..a26f05484 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django>=1.4 +Django>=1.4.2 django-mptt>=0.4 Pillow feedparser>=5.1.2 From 3f11338c3089d419ddebb2f858699a089ddc64c7 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 29 Aug 2013 16:58:56 +0200 Subject: [PATCH 0729/1590] Emit a warning if the tree_editor detects an incorrect MPTT structure. This usually shows up as items appearing in wrong places in the tree. --- feincms/admin/tree_editor.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 5a95e7b62..4346a4864 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -63,10 +63,13 @@ def _build_tree_structure(cls): all_nodes[p_id] = [] if parent_id: - if not all_nodes.has_key(parent_id): + if parent_id not in all_nodes: # This happens very rarely, but protect against parents that - # we have yet to iteratove over. + # we have yet to iteratove over. Happens with broken MPTT + # hierarchy. all_nodes[parent_id] = [] + logger.warn("Incorrect MPTT hierarchy for %s, node %d has left_attr < than one of its parents. Try rebuilding mptt data (use '%s._default_manager.rebuild()').", cls.__name__, p_id, cls.__name__) + all_nodes[parent_id].append(p_id) return all_nodes From bc9dedaa89ad82a40ee1155f3274829c5f52be8a Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 19 Aug 2013 13:59:51 +0200 Subject: [PATCH 0730/1590] Run tests with Django 1.4.2, as newer django-mptt requires that --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a188143c..510d5d706 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,11 @@ python: - "2.7" - "2.6" env: - - DJANGO_VERSION=1.4.0 + - DJANGO_VERSION=1.4.2 - DJANGO_VERSION=1.5.0 # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q Django==$DJANGO_VERSION django-mptt Pillow feedparser --use-mirrors - python setup.py -q install # command to run tests, e.g. python setup.py test -script: "cd tests && ./manage.py test testapp" \ No newline at end of file +script: "cd tests && ./manage.py test testapp" From f8331eaf47859273632577dacb517085b6a4e61b Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 19 Aug 2013 14:04:39 +0200 Subject: [PATCH 0731/1590] Codify req on django >= 1.4.2 for django-mptt requiring that --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ba0e73b48..dac4bfba2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django>=1.4 +Django>=1.4.2 django-mptt>=0.4 PIL feedparser>=5.1.2 From 1aaa19603f5f777d9b7f0083d4999ac5ee1cde1f Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 9 Sep 2013 14:11:28 +0200 Subject: [PATCH 0732/1590] Some weird images would trigger and exception that raised an exception in the exception handler, thus breaking the medialibrary admin interface. ValueError actually has no strerror, so just stringify the whole exception and hope for the best. --- feincms/module/medialibrary/modeladmins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index aa4d19ed6..65397e54b 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -159,7 +159,7 @@ def file_type(self, obj): if d: t += " %d×%d" % ( d[0], d[1] ) except (IOError, ValueError), e: - t += " (%s)" % e.strerror + t += " (%s)" % e return t file_type.admin_order_field = 'type' file_type.short_description = _('file type') From 6ba07c2aa9a24573e7845fd06fa3d92400c37b5a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 13 Sep 2013 14:00:59 +0200 Subject: [PATCH 0733/1590] Full specification of dependency versions in tox.ini, update the list of envs --- .gitignore | 4 ++++ tests/tox.ini | 54 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index cfd965a3f..bdf8a629b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ /dist tests/test.zip /docs/_build +/tests/.tox +/tests/.coverage +/tests/venv +/tests/htmlcov diff --git a/tests/tox.ini b/tests/tox.ini index 208fb8522..148a1a98c 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -2,35 +2,51 @@ setupdir = .. distribute = False envlist = - py25-1.4.X, py26-1.4.X, py27-1.4.X, + py26-1.4.X, + py27-1.4.X, + py26-1.5.X, + py27-1.5.X, [testenv] downloadcache = {toxworkdir}/_download/ commands = - {envbindir}/django-admin.py test {posargs:tests} --settings=tests.settings + {envpython} manage.py test {posargs:testapp} --settings=testapp.settings setenv = - PYTHONPATH = {toxworkdir}/../.. - -[testenv:py25-1.4.X] -basepython = python2.5 -deps = - django==1.4 - PIL==1.1.7 - feedparser - lxml + PYTHONPATH = .:{toxworkdir}/../.. [testenv:py26-1.4.X] basepython = python2.6 deps = - django==1.4 - PIL==1.1.7 - feedparser - lxml + django==1.4.7 + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 [testenv:py27-1.4.X] basepython = python2.7 deps = - django==1.4 - PIL==1.1.7 - feedparser - lxml + django==1.4.7 + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + + +[testenv:py26-1.5.X] +basepython = python2.6 +deps = + django==1.5.3 + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + +[testenv:py27-1.5.X] +basepython = python2.7 +deps = + django==1.5.3 + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 From 88b26e666c983762e905dadf9ba4aedd21eb3957 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 13 Sep 2013 14:03:03 +0200 Subject: [PATCH 0734/1590] Make tox actually run tests --- tests/tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/tox.ini b/tests/tox.ini index 148a1a98c..92cd4b47a 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -10,9 +10,10 @@ envlist = [testenv] downloadcache = {toxworkdir}/_download/ commands = - {envpython} manage.py test {posargs:testapp} --settings=testapp.settings + {envpython} manage.py test {posargs:feincms} --settings=testapp.settings setenv = PYTHONPATH = .:{toxworkdir}/../.. + FEINCMS_RUN_TESTS = 1 [testenv:py26-1.4.X] basepython = python2.6 From a73eabc51012f12d1c7864c1dcd283c4447e8829 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 13 Sep 2013 14:04:06 +0200 Subject: [PATCH 0735/1590] BeautifulSoup is also a dependency of the testsuite --- tests/tox.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/tox.ini b/tests/tox.ini index 92cd4b47a..145715d42 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -23,6 +23,7 @@ deps = Pillow==2.1.0 feedparser==5.1.3 lxml==3.2.3 + BeautifulSoup==3.2.1 [testenv:py27-1.4.X] basepython = python2.7 @@ -32,7 +33,7 @@ deps = Pillow==2.1.0 feedparser==5.1.3 lxml==3.2.3 - + BeautifulSoup==3.2.1 [testenv:py26-1.5.X] basepython = python2.6 @@ -42,6 +43,7 @@ deps = Pillow==2.1.0 feedparser==5.1.3 lxml==3.2.3 + BeautifulSoup==3.2.1 [testenv:py27-1.5.X] basepython = python2.7 @@ -51,3 +53,4 @@ deps = Pillow==2.1.0 feedparser==5.1.3 lxml==3.2.3 + BeautifulSoup==3.2.1 From 153b781cba9ff1ec72f8705b6cff08918da60458 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 13 Sep 2013 14:16:17 +0200 Subject: [PATCH 0736/1590] Add tox configuration for running the testsuite with the upcoming Django 1.6 --- feincms/tests/__init__.py | 6 ++--- feincms/tests/{cms_tests.py => test_cms.py} | 0 feincms/tests/{page_tests.py => test_page.py} | 0 feincms/tests/{tests.py => test_stuff.py} | 6 ----- tests/testapp/models.py | 6 +++++ tests/tox.ini | 22 +++++++++++++++++++ 6 files changed, 31 insertions(+), 9 deletions(-) rename feincms/tests/{cms_tests.py => test_cms.py} (100%) rename feincms/tests/{page_tests.py => test_page.py} (100%) rename feincms/tests/{tests.py => test_stuff.py} (96%) diff --git a/feincms/tests/__init__.py b/feincms/tests/__init__.py index 75f3aa027..183393e38 100644 --- a/feincms/tests/__init__.py +++ b/feincms/tests/__init__.py @@ -7,8 +7,8 @@ import os if os.environ.get('FEINCMS_RUN_TESTS'): - from .cms_tests import * - from .page_tests import * - from .tests import * + from .test_cms import * + from .test_page import * + from .test_stuff import * # ------------------------------------------------------------------------ diff --git a/feincms/tests/cms_tests.py b/feincms/tests/test_cms.py similarity index 100% rename from feincms/tests/cms_tests.py rename to feincms/tests/test_cms.py diff --git a/feincms/tests/page_tests.py b/feincms/tests/test_page.py similarity index 100% rename from feincms/tests/page_tests.py rename to feincms/tests/test_page.py diff --git a/feincms/tests/tests.py b/feincms/tests/test_stuff.py similarity index 96% rename from feincms/tests/tests.py rename to feincms/tests/test_stuff.py index a6a81a423..8aa7c97c3 100644 --- a/feincms/tests/tests.py +++ b/feincms/tests/test_stuff.py @@ -90,12 +90,6 @@ class ExampleCMSBase2(Base): Page.register_response_processor(processors.debug_sql_queries_response_processor()) -Entry.register_extensions( - 'feincms.module.extensions.seo', - 'feincms.module.extensions.translations', - 'feincms.module.extensions.seo', - 'feincms.module.extensions.ct_tracker', - ) class BlogTestCase(TestCase): def setUp(self): u = User(username='test', is_active=True, is_staff=True, is_superuser=True) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 502bf7355..b6fa6d39f 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -48,6 +48,12 @@ def get_admin_fields(form, *args, **kwargs): )) +Entry.register_extensions( + 'feincms.module.extensions.seo', + 'feincms.module.extensions.translations', + 'feincms.module.extensions.seo', + 'feincms.module.extensions.ct_tracker', + ) Entry.register_regions( ('main', 'Main region'), ) diff --git a/tests/tox.ini b/tests/tox.ini index 145715d42..d92d7e3c6 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -6,6 +6,8 @@ envlist = py27-1.4.X, py26-1.5.X, py27-1.5.X, + py26-1.6.X, + py27-1.6.X, [testenv] downloadcache = {toxworkdir}/_download/ @@ -54,3 +56,23 @@ deps = feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 + +[testenv:py26-1.6.X] +basepython = python2.6 +deps = + --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + BeautifulSoup==3.2.1 + +[testenv:py27-1.6.X] +basepython = python2.7 +deps = + --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + BeautifulSoup==3.2.1 From 5d31fff3fac45b051fb87d76bf900a40b436c954 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 13 Sep 2013 15:12:26 +0200 Subject: [PATCH 0737/1590] (Partial?) Fix ensure_completely_loaded, testsuite passes with Django 1.4, 1.5, 1.6 --- feincms/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feincms/__init__.py b/feincms/__init__.py index b2992ce3b..35c395d6d 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -58,6 +58,10 @@ def ensure_completely_loaded(force=False): except AttributeError: pass + # Randomly call some cache filling methods + # http://goo.gl/XNI2qz + model._meta._fill_fields_cache() + # Calls to get_models(...) are cached by the arguments used in the call. # This cache is normally cleared in loading.register_models(), but we # invalidate the get_models() cache, by calling get_models From a3962f7823840aa548a259e424443f2cadc1bdc4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 13 Sep 2013 16:28:56 +0200 Subject: [PATCH 0738/1590] Also add a tox.ini section for running the testsuite with Django@master --- tests/tox.ini | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/tox.ini b/tests/tox.ini index d92d7e3c6..3b56ce4e9 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -8,6 +8,7 @@ envlist = py27-1.5.X, py26-1.6.X, py27-1.6.X, + py27-1.7.X, [testenv] downloadcache = {toxworkdir}/_download/ @@ -76,3 +77,13 @@ deps = feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 + +[testenv:py27-1.7.X] +basepython = python2.7 +deps = + --editable=git+git://github.com/django/django.git@master#egg=django-dev + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + BeautifulSoup==3.2.1 From cd8071ee0ed0fe5b13049cc362ebc5b14096a99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= Date: Sun, 15 Sep 2013 22:39:53 +0200 Subject: [PATCH 0739/1590] refactor tests so extensions are not loaded by default --- tests/testapp/tests/test_page.py | 18 +++++++++++++++ tests/testapp/tests/test_stuff.py | 11 --------- tests/testapp/tests/utils.py | 38 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 tests/testapp/tests/utils.py diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 36f52f9cd..0cae626f1 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -38,10 +38,28 @@ from feincms.translations import short_language_code from .test_stuff import Empty +from .utils import reset_page_db # ------------------------------------------------------------------------ class PagesTestCase(TestCase): + + @classmethod + def setUpClass(cls): + Page.register_extensions( + 'feincms.module.extensions.datepublisher', + 'feincms.module.extensions.translations', + 'feincms.module.extensions.ct_tracker', + 'feincms.module.extensions.seo', + 'feincms.module.extensions.changedate', + 'feincms.module.extensions.seo', # duplicate + 'feincms.module.page.extensions.navigation', + 'feincms.module.page.extensions.symlinks', + 'feincms.module.page.extensions.titles', + ) + reset_page_db() + + def setUp(self): u = User(username='test', is_active=True, is_staff=True, is_superuser=True) u.set_password('test') diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index da77e6296..ef3afe8b3 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -74,17 +74,6 @@ class ExampleCMSBase2(Base): ExampleCMSBase2.register_regions(('region', 'region title'), ('region2', 'region2 title')) -Page.register_extensions( - 'feincms.module.extensions.datepublisher', - 'feincms.module.extensions.translations', - 'feincms.module.extensions.ct_tracker', - 'feincms.module.extensions.seo', - 'feincms.module.extensions.changedate', - 'feincms.module.extensions.seo', # duplicate - 'feincms.module.page.extensions.navigation', - 'feincms.module.page.extensions.symlinks', - 'feincms.module.page.extensions.titles', - ) Page.create_content_type(ContactFormContent, form=ContactForm) Page.create_content_type(FileContent) Page.register_request_processor(processors.etag_request_processor) diff --git a/tests/testapp/tests/utils.py b/tests/testapp/tests/utils.py new file mode 100644 index 000000000..80c7a20d1 --- /dev/null +++ b/tests/testapp/tests/utils.py @@ -0,0 +1,38 @@ +# coding: utf-8 +from django.core.management import CommandError +from django.core.management.color import no_style +from django.core.management.sql import sql_delete, sql_all +from django.db import connections, transaction, DEFAULT_DB_ALIAS +import feincms.models + +import datetime + +def mock_datetime(): + class MockDatetime(datetime.datetime): + @classmethod + def now(cls): + return datetime.datetime(2012, 6, 1) + return MockDatetime + +def mock_date(): + class MockDate(datetime.date): + @classmethod + def today(cls): + return datetime.date(2012, 6, 1) + return MockDate + + +def reset_page_db(): + using = DEFAULT_DB_ALIAS + connection = connections[using] + sql_list = sql_delete(feincms.module.page.models, no_style(), connection) + sql_list += sql_all(feincms.module.page.models, no_style(), connection) + try: + cursor = connection.cursor() + for sql in sql_list: + cursor.execute(sql) + except Exception, e: + transaction.rollback_unless_managed() + raise CommandError("Error: database couldn't be reset: %s" % e) + else: + transaction.commit_unless_managed() From dd89356acfd2600c3ff4c6a6a5acdfd7c932cff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4chler?= Date: Sun, 15 Sep 2013 23:08:18 +0200 Subject: [PATCH 0740/1590] add extensions test --- tests/testapp/tests/__init__.py | 1 + tests/testapp/tests/test_extensions.py | 74 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/testapp/tests/test_extensions.py diff --git a/tests/testapp/tests/__init__.py b/tests/testapp/tests/__init__.py index 99ddd0c50..734127365 100644 --- a/tests/testapp/tests/__init__.py +++ b/tests/testapp/tests/__init__.py @@ -7,5 +7,6 @@ from .test_cms import * from .test_page import * from .test_stuff import * +from .test_extensions import * # ------------------------------------------------------------------------ diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py new file mode 100644 index 000000000..5fc28873c --- /dev/null +++ b/tests/testapp/tests/test_extensions.py @@ -0,0 +1,74 @@ +# coding: utf-8 +from __future__ import absolute_import + +from django.template.defaultfilters import slugify +from django.test.utils import override_settings +from django.test import TestCase +from django.contrib.sites.models import Site + +from feincms.module.page.models import Page + + +from .utils import reset_page_db + + + +class TranslationTestCase(TestCase): + + @classmethod + def setUpClass(cls): + Page.register_extensions('feincms.module.extensions.translations',) + reset_page_db() + + def setUp(self): + Page.register_templates({ + 'key': 'base', + 'title': 'Standard template', + 'path': 'feincms_base.html', + 'regions': ( + ('main', 'Main content area'), + ('sidebar', 'Sidebar', 'inherited'), + ), + }) + self.site_1 = Site.objects.all()[0] + + # create a bunch of pages + en = self.create_default_page_set(language='en') + de = self.create_default_page_set(language='de', title=u'Testseite') + de.translation_of = en + de.save() + de.parent.translation_of = en.parent + de.parent.save() + self.page_de = de.parent + self.page_en = en.parent + + + def create_page(self, title='Test page', parent=None, **kwargs): + defaults = { + 'template_key': 'base', + 'site': self.site_1, + 'in_navigation': False, + 'active': False, + } + defaults.update(kwargs) + return Page.objects.create( + title=title, + slug=kwargs.get('slug', slugify(title)), + parent=parent, + **defaults) + + def create_default_page_set(self, **kwargs): + return self.create_page( + 'Test child page', + parent=self.create_page(**kwargs), + ) + + def testPage(self): + page = Page() + self.assertTrue(hasattr(page, 'language')) + self.assertTrue(hasattr(page, 'translation_of')) + self.assertEquals(self.page_de.translation_of, self.page_en) + self.assertEquals(self.page_de.original_translation, self.page_en) + + # TODO: add request tests + # with translation.override('de'): \ No newline at end of file From 202a045f2ce6ca5275930579ae724b737b13f099 Mon Sep 17 00:00:00 2001 From: David Evans Date: Tue, 17 Sep 2013 10:34:00 +0100 Subject: [PATCH 0741/1590] Use `static` templatetag rather than `STATIC_URL` This allows us to use the CachedStaticFilesStorage which gives unique names for each version of a static file. --- feincms/admin/tree_editor.py | 7 ++++--- feincms/module/page/modeladmins.py | 9 +++++---- feincms/templates/admin/content/table/init.html | 4 ++-- feincms/templates/admin/feincms/_regions_js.html | 3 ++- feincms/templates/admin/feincms/fe_editor.html | 4 ++-- feincms/templates/admin/feincms/fe_tools.html | 8 ++++---- feincms/templates/admin/feincms/item_editor.html | 6 +++--- .../templates/admin/feincms/load-jquery.include | 7 ++++--- feincms/templates/admin/feincms/tree_editor.html | 14 +++++++------- 9 files changed, 33 insertions(+), 29 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 4346a4864..37510733a 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -5,11 +5,11 @@ import json import logging -from django.conf import settings as django_settings from django.contrib import admin from django.contrib.admin.views import main from django.contrib.admin.actions import delete_selected from django.db import router +from django.contrib.staticfiles.templatetags.staticfiles import static from django.db.models import Q from django.http import (HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, HttpResponseServerError) @@ -39,8 +39,9 @@ def django_boolean_icon(field_val, alt_text=None, title=None): title = 'title="%s" ' % title else: title = '' - return mark_safe(u'%s' % - (django_settings.STATIC_URL, BOOLEAN_MAPPING[field_val], alt_text, title)) + icon_url = static('feincms/img/icon-%s.gif' % BOOLEAN_MAPPING[field_val]) + return mark_safe(u'%s' % + (icon_url, alt_text, title)) def _build_tree_structure(cls): diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index f55f4039c..0c6099445 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -7,6 +7,7 @@ from django.conf import settings as django_settings from django.core.exceptions import PermissionDenied from django.contrib.contenttypes.models import ContentType +from django.contrib.staticfiles.templatetags.staticfiles import static from django.contrib import admin from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect @@ -114,22 +115,22 @@ def _actions_column(self, page): actions.insert( 0, u'' - u'%s' + u'%s' u'' % ( page.pk, _('Add child page'), - django_settings.STATIC_URL, + static('feincms/img/icon_addlink.gif'), _('Add child page'), ) ) actions.insert( 0, u'' - u'%s' + u'%s' u'' % ( preview_url, _('View on site'), - django_settings.STATIC_URL, + static('feincms/img/selector-search.gif'), _('View on site'), ) ) diff --git a/feincms/templates/admin/content/table/init.html b/feincms/templates/admin/content/table/init.html index ab427dd1c..1f4b263e1 100644 --- a/feincms/templates/admin/content/table/init.html +++ b/feincms/templates/admin/content/table/init.html @@ -1,5 +1,5 @@ -{% load i18n %} - +{% load i18n staticfiles %} + + {% include "admin/feincms/_messages_js.html" %} {% include "admin/feincms/_regions_js.html" %} diff --git a/feincms/templates/admin/feincms/fe_tools.html b/feincms/templates/admin/feincms/fe_tools.html index 48ea3a1fe..c2b2f920c 100644 --- a/feincms/templates/admin/feincms/fe_tools.html +++ b/feincms/templates/admin/feincms/fe_tools.html @@ -1,11 +1,11 @@ -{% load i18n %} +{% load i18n staticfiles %} {% load url from future %} - - + +
{% trans "Stop Editing" %} diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index d21458a3c..15a24bbb5 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -1,13 +1,13 @@ {% extends "admin/change_form.html" %} -{% load i18n admin_modify %} +{% load i18n admin_modify staticfiles %} {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} {% include "admin/feincms/load-jquery.include" %} {% endblock %} - - + + {% include "admin/feincms/_messages_js.html" %} {% include "admin/feincms/_regions_js.html" %} diff --git a/feincms/templates/admin/feincms/load-jquery.include b/feincms/templates/admin/feincms/load-jquery.include index 9926abfa8..62dd22b53 100644 --- a/feincms/templates/admin/feincms/load-jquery.include +++ b/feincms/templates/admin/feincms/load-jquery.include @@ -1,11 +1,12 @@ +{% load staticfiles %} {% comment %} Include jquery, override this template if you want to use a cdn version or load more plugins or whatnot {% endcomment %} - - - + + + - - - - + + + + {% endblock %} From bfcd64872e22159c22900d47181114a034e0c970 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac Date: Mon, 30 Sep 2013 11:47:49 +0200 Subject: [PATCH 0742/1590] Update context_processors.py Remove obsolete documentation. --- feincms/context_processors.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/feincms/context_processors.py b/feincms/context_processors.py index a74385c3a..ae9638d96 100644 --- a/feincms/context_processors.py +++ b/feincms/context_processors.py @@ -3,9 +3,7 @@ def add_page_if_missing(request): """ - If this attribute exists, then a page object has been registered already - by some other part of the code. We let it decide which page object it - wants to pass into the template + Returns ``feincms_page`` for request. """ try: From 83d4fbfec8a02bed8ed4aa54eeb90118fff78181 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 30 Sep 2013 13:39:48 +0200 Subject: [PATCH 0743/1590] Stop adding methods to admin_cls, this does not work with LegacyExtension under certain circumstances --- feincms/module/extensions/datepublisher.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index f6ef0f6a2..cec7d7d43 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -94,15 +94,15 @@ def granular_save(obj, *args, **kwargs): # Processor to patch up response headers for expiry date cls.register_response_processor(datepublisher_response_processor) - def datepublisher_admin(self, page): + def datepublisher_admin(self): return u'%s – %s' % ( - format_date(page.publication_date), - format_date(page.publication_end_date, '∞'), + format_date(self.publication_date), + format_date(self.publication_end_date, '∞'), ) datepublisher_admin.allow_tags = True datepublisher_admin.short_description = _('visible from - to') - admin_cls.datepublisher_admin = datepublisher_admin + cls.datepublisher_admin = datepublisher_admin try: pos = admin_cls.list_display.index('is_visible_admin') except ValueError: From a765206b9058bcce7faee1341e6384506b7d5a29 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 16 Sep 2013 16:02:34 +0200 Subject: [PATCH 0744/1590] Add support for Python 3.3 (successfully run the testsuite at least) --- docs/admin.rst | 4 +- docs/integration.rst | 2 +- example/models.py | 6 +-- feincms/admin/item_editor.py | 4 +- feincms/admin/tree_editor.py | 17 +++---- feincms/content/richtext/models.py | 2 +- feincms/contrib/fields.py | 22 +++++---- feincms/extensions.py | 3 +- feincms/management/checker.py | 12 +++-- .../commands/medialibrary_orphans.py | 4 +- feincms/models.py | 24 ++++++---- feincms/module/blog/models.py | 6 ++- feincms/module/medialibrary/modeladmins.py | 11 +++-- feincms/module/medialibrary/models.py | 18 ++++--- feincms/module/mixins.py | 4 +- feincms/module/page/extensions/navigation.py | 4 +- feincms/module/page/models.py | 6 ++- .../page/templatetags/feincms_page_tags.py | 4 +- feincms/templatetags/feincms_admin_tags.py | 2 +- feincms/templatetags/feincms_thumbnail.py | 20 ++++---- feincms/templatetags/fragment_tags.py | 3 +- feincms/translations.py | 10 ++-- feincms/utils/__init__.py | 24 +++------- feincms/utils/templatetags.py | 8 +++- feincms/views/cbv/views.py | 2 +- tests/testapp/models.py | 5 +- tests/testapp/tests/test_cms.py | 4 +- tests/testapp/tests/test_extensions.py | 4 +- tests/testapp/tests/test_page.py | 48 ++++++++++--------- tests/testapp/tests/test_stuff.py | 27 +++++++++-- tests/testapp/tests/utils.py | 2 +- tests/tox.ini | 11 +++++ 32 files changed, 187 insertions(+), 136 deletions(-) diff --git a/docs/admin.rst b/docs/admin.rst index 20fc8a99e..537187750 100644 --- a/docs/admin.rst +++ b/docs/admin.rst @@ -51,7 +51,7 @@ All standard :class:`~django.contrib.admin.options.ModelAdmin` attributes such a :attr:`ModelAdmin.list_display`, :attr:`ModelAdmin.list_editable`, :attr:`ModelAdmin.list_filter` work as normally. The only exception to this rule is the column showing the tree structure (the second column in the image). -There, we always show the value of :attr:`Model.__unicode__` currently. +There, we always show the value of :attr:`Model.__str__` currently. AJAX checkboxes @@ -83,7 +83,7 @@ Usage:: mptt.register(Category) class CategoryAdmin(tree_editor.TreeEditor): - list_display = ('__unicode__', 'active_toggle') + list_display = ('__str__', 'active_toggle') active_toggle = tree_editor.ajax_editable_boolean('active', _('active')) diff --git a/docs/integration.rst b/docs/integration.rst index c30e419e7..793e8fb68 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -150,7 +150,7 @@ Django's standard functionality:: class Meta: ordering = ['-id'] - def __unicode__(self): + def __str__(self): return self.title @app_models.permalink diff --git a/example/models.py b/example/models.py index f932dd879..3e50ff0ae 100644 --- a/example/models.py +++ b/example/models.py @@ -1,5 +1,6 @@ from django import forms from django.db import models +from django.utils.encoding import python_2_unicode_compatible from django.utils.text import capfirst from django.utils.translation import ugettext_lazy as _ @@ -78,6 +79,7 @@ def children(self, page, **kwargs): ) +@python_2_unicode_compatible class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() @@ -88,12 +90,10 @@ class Meta: verbose_name = 'category' verbose_name_plural = 'categories' - def __unicode__(self): + def __str__(self): return self.name # add m2m field to entry so it shows up in entry admin Entry.add_to_class('categories', models.ManyToManyField(Category, blank=True, null=True)) EntryAdmin.list_filter += ('categories',) - - diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 60b6499ea..4a3f2eed1 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -14,7 +14,7 @@ from django.forms.models import modelform_factory from django.http import Http404 from django.shortcuts import render_to_response -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from django.utils.functional import curry from django.utils.translation import ugettext as _ @@ -166,7 +166,7 @@ def _frontend_editing_view(self, request, cms_id, content_type, content_id): context = self.get_extra_context(request) context.update({ 'frontend_editing': True, - 'title': _('Change %s') % force_unicode(model_cls._meta.verbose_name), + 'title': _('Change %s') % force_text(model_cls._meta.verbose_name), 'object': obj, 'form': form, 'is_popup': True, diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 37510733a..6e81629a4 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -2,6 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from functools import reduce import json import logging @@ -16,7 +17,7 @@ from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _, ugettext -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from mptt.exceptions import InvalidMove from mptt.forms import MPTTAdminForm @@ -92,7 +93,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): (useful for "disabled and you can't change it" situations). """ if text: - text = ' (%s)' % unicode(text) + text = u' (%s)' % text if override is not None: a = [ django_boolean_icon(override, text), text ] @@ -108,7 +109,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): a.insert(0, '
' % ( attr, item.pk )) a.append('
') - return unicode(''.join(a)) + return u''.join(a) # ------------------------------------------------------------------------ def ajax_editable_boolean(attr, short_description): @@ -119,7 +120,7 @@ def ajax_editable_boolean(attr, short_description): Example:: class MyTreeEditor(TreeEditor): - list_display = ('__unicode__', 'active_toggle') + list_display = ('__str__', 'active_toggle') active_toggle = ajax_editable_boolean('active', _('is active')) """ @@ -247,7 +248,7 @@ def indented_short_title(self, item): if hasattr(item, 'short_title') and callable(item.short_title): r += escape(item.short_title()) else: - r += escape(unicode(item)) + r += escape(u'%s' % item) # r += '' return mark_safe(r) indented_short_title.short_description = _('title') @@ -432,8 +433,8 @@ def _move_node(self, request): if position in ('last-child', 'left', 'right'): try: tree_manager.move_node(cut_item, pasted_on, position) - except InvalidMove, e: - self.message_user(request, unicode(e)) + except InvalidMove as e: + self.message_user(request, u'%s' % e) return HttpResponse('FAIL') # Ensure that model save has been run @@ -470,7 +471,7 @@ def delete_selected_tree(self, modeladmin, request, queryset): if self.has_delete_permission(request, obj): obj.delete() n += 1 - obj_display = force_unicode(obj) + obj_display = force_text(obj) self.log_deletion(request, obj, obj_display) else: logger.warning( diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index a0a340d97..8680646b5 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -114,5 +114,5 @@ def func_im(self, *args, **kwargs): # Make sure we can load the tidy function without dependency failures: try: get_object(settings.FEINCMS_TIDY_FUNCTION) - except ImportError, e: + except ImportError as e: raise ImproperlyConfigured("FEINCMS_TIDY_HTML is enabled but the HTML tidy function %s could not be imported: %s" % (settings.FEINCMS_TIDY_FUNCTION, e)) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index fea195bac..925931720 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -4,20 +4,23 @@ from django import forms from django.db import models from django.core.serializers.json import DjangoJSONEncoder +from django.utils import six class JSONFormField(forms.fields.CharField): def clean(self, value, *args, **kwargs): if value: try: - # Run the value through JSON so we can normalize formatting and at least learn about malformed data: + # Run the value through JSON so we can normalize formatting + # and at least learn about malformed data: value = json.dumps(json.loads(value), cls=DjangoJSONEncoder) except ValueError: raise forms.ValidationError("Invalid JSON data!") return super(JSONFormField, self).clean(value, *args, **kwargs) -class JSONField(models.TextField): + +class JSONField(six.with_metaclass(models.SubfieldBase, models.TextField)): """ TextField which transparently serializes/unserializes JSON objects @@ -25,9 +28,6 @@ class JSONField(models.TextField): http://www.djangosnippets.org/snippets/1478/ """ - # Used so to_python() is called - __metaclass__ = models.SubfieldBase - formfield = JSONFormField def to_python(self, value): @@ -35,7 +35,8 @@ def to_python(self, value): if isinstance(value, dict): return value - elif isinstance(value, basestring): + elif (isinstance(value, six.string_types) + or isinstance(value, six.binary_type)): # Avoid asking the JSON decoder to handle empty values: if not value: return {} @@ -72,15 +73,18 @@ def _flatten_value(self, value): if isinstance(value, dict): value = json.dumps(value, cls=DjangoJSONEncoder) - assert isinstance(value, basestring) + assert isinstance(value, six.string_types) return value + try: from south.modelsinspector import add_introspection_rules - JSONField_introspection_rule = ( (JSONField,), [], {}, ) + JSONField_introspection_rule = ((JSONField,), [], {},) - add_introspection_rules(rules=[JSONField_introspection_rule], patterns=["^feincms\.contrib\.fields"]) + add_introspection_rules( + rules=[JSONField_introspection_rule], + patterns=["^feincms\.contrib\.fields"]) except ImportError: pass diff --git a/feincms/extensions.py b/feincms/extensions.py index 5bb991d69..ed8bd62fc 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -7,6 +7,7 @@ from django.contrib import admin from django.core.exceptions import ImproperlyConfigured +from django.utils import six from feincms.utils import get_object @@ -43,7 +44,7 @@ def register_extensions(cls, *extensions): extension = None - if isinstance(ext, basestring): + if isinstance(ext, six.string_types): try: extension = get_object(ext) except (AttributeError, ImportError, ValueError): diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 627cd9f77..b52668741 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -1,3 +1,5 @@ +from __future__ import print_function + from django.core.management.color import color_style from django.db import connection @@ -39,17 +41,17 @@ def _fn(sender, **kwargs): style = color_style() - print style.ERROR('The following columns seem to be missing in the database table %s:' % cls._meta.db_table) + print(style.ERROR('The following columns seem to be missing in the database table %s:' % cls._meta.db_table)) for field in missing_columns: - print u'%s:%s%s' % ( + print(u'%s:%s%s' % ( style.SQL_KEYWORD(field.column), ' ' * (25 - len(field.column)), u'%s.%s' % (field.__class__.__module__, field.__class__.__name__), - ) + )) - print style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to' + print(style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to' ' find out what the correct column types are. (Or use south, which is what' ' you should be doing anyway.)\n' % ( cls._meta.app_label, - )) + ))) return _fn diff --git a/feincms/management/commands/medialibrary_orphans.py b/feincms/management/commands/medialibrary_orphans.py index 7a4e11191..4f1b50d70 100644 --- a/feincms/management/commands/medialibrary_orphans.py +++ b/feincms/management/commands/medialibrary_orphans.py @@ -1,7 +1,7 @@ import os from django.core.management.base import NoArgsCommand -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text from feincms.module.medialibrary.models import MediaFile @@ -16,5 +16,5 @@ def handle_noargs(self, **options): for base, dirs, files in os.walk('media/medialibrary'): for f in files: full = os.path.join(base[6:], f) - if force_unicode(full) not in mediafiles: + if force_text(full) not in mediafiles: print os.path.join(base, f) diff --git a/feincms/models.py b/feincms/models.py index 609bbc725..c93e5c980 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -5,6 +5,7 @@ the feincms\_ namespace. """ +from functools import reduce import sys import operator import warnings @@ -18,7 +19,7 @@ from django.forms.widgets import Media from django.template.loader import render_to_string from django.utils.datastructures import SortedDict -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from feincms import ensure_completely_loaded @@ -26,6 +27,7 @@ from feincms.utils import copy_model_instance +@python_2_unicode_compatible class Region(object): """ This class represents a region inside a template. Example regions might be @@ -38,8 +40,8 @@ def __init__(self, key, title, *args): self.inherited = args and args[0] == 'inherited' or False self._content_types = [] - def __unicode__(self): - return force_unicode(self.title) + def __str__(self): + return force_text(self.title) @property def content_types(self): @@ -52,6 +54,7 @@ def content_types(self): for ct in self._content_types] +@python_2_unicode_compatible class Template(object): """ A template is a standard Django template which is used to render a @@ -81,8 +84,8 @@ def _make_region(data): self.regions = [_make_region(row) for row in regions] self.regions_dict = dict((r.key, r) for r in self.regions) - def __unicode__(self): - return force_unicode(self.title) + def __str__(self): + return force_text(self.title) class ContentProxy(object): @@ -227,7 +230,7 @@ def _fetch_regions(self): self._cache['regions'] = dict(( region, sorted(instances, key=lambda c: c.ordering), - ) for region, instances in contents.iteritems()) + ) for region, instances in contents.items()) return self._cache['regions'] @@ -295,6 +298,7 @@ def create_base_model(inherit_from=models.Model): extend :class:`django.db.models.Model`. """ + @python_2_unicode_compatible class Base(inherit_from, ExtensionsMixin): """ This is the base class for your CMS models. It knows how to create and @@ -439,7 +443,7 @@ class Meta: app_label = cls._meta.app_label ordering = ['ordering'] - def __unicode__(self): + def __str__(self): return u'%s, region=%s, ordering=%d>' % ( self.__class__.__name__, self.pk, self.parent.__class__.__name__, self.parent.pk, self.parent, @@ -505,7 +509,7 @@ def get_queryset(cls, filter_args): # from, therefore we ensure that the # module is always known. '__module__': cls.__module__, - '__unicode__': __unicode__, + '__str__': __str__, 'render': render, 'fe_render': fe_render, 'fe_identifier': fe_identifier, @@ -527,7 +531,8 @@ def get_queryset(cls, filter_args): % (cls.__module__, name, cls.__module__, cls.__name__), RuntimeWarning) - cls._feincms_content_model = type(name, (models.Model,), attrs) + cls._feincms_content_model = python_2_unicode_compatible( + type(name, (models.Model,), attrs)) # list of concrete content types @@ -817,5 +822,6 @@ def register_with_reversion(cls): return Base + # Legacy support Base = create_base_model() diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index 8300d0412..e266936c2 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -8,6 +8,7 @@ from django.db import models from django.db.models import signals from django.utils import timezone +from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from feincms.admin import item_editor @@ -24,6 +25,7 @@ def published(self): ) +@python_2_unicode_compatible class Entry(Base): published = models.BooleanField(_('published'), default=False) title = models.CharField(_('title'), max_length=100, @@ -41,7 +43,7 @@ class Meta: objects = EntryManager() - def __unicode__(self): + def __str__(self): return self.title def save(self, *args, **kwargs): @@ -60,7 +62,7 @@ def get_absolute_url(self): class EntryAdmin(item_editor.ItemEditor): date_hierarchy = 'published_on' - list_display = ['__unicode__', 'published', 'published_on'] + list_display = ['__str__', 'published', 'published_on'] list_filter = ['published',] search_fields = ['title', 'slug'] prepopulated_fields = { diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 65397e54b..6f785a3e2 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -18,6 +18,7 @@ from django.shortcuts import render_to_response from django.template.context import RequestContext from django.template.defaultfilters import filesizeformat +from django.utils.encoding import python_2_unicode_compatible from django.utils.safestring import mark_safe from django.utils.translation import ungettext, ugettext_lazy as _ from django.views.decorators.csrf import csrf_protect @@ -84,7 +85,7 @@ def save_as_zipfile(modeladmin, request, queryset): try: zip_name = export_zipfile(site, queryset) messages.info(request, _("ZIP file exported as %s") % zip_name) - except Exception, e: + except Exception as e: messages.error(request, _("ZIP file export failed: %s") % str(e)) return @@ -99,8 +100,8 @@ class MediaFileAdmin(ExtensionModelAdmin): save_on_top = True date_hierarchy = 'created' inlines = [admin_translationinline(MediaFileTranslation)] - list_display = ['admin_thumbnail', '__unicode__', 'file_info', 'formatted_created'] - list_display_links = ['__unicode__'] + list_display = ['admin_thumbnail', '__str__', 'file_info', 'formatted_created'] + list_display_links = ['__str__'] list_filter = ['type', 'categories'] list_per_page = 25 search_fields = ['copyright', 'file', 'translations__caption'] @@ -158,7 +159,7 @@ def file_type(self, obj): d = get_image_dimensions(obj.file.file) if d: t += " %d×%d" % ( d[0], d[1] ) - except (IOError, ValueError), e: + except (IOError, ValueError) as e: t += " (%s)" % e return t file_type.admin_order_field = 'type' @@ -196,7 +197,7 @@ def bulk_upload(request): try: count = import_zipfile(request.POST.get('category'), request.POST.get('overwrite', False), request.FILES['data']) messages.info(request, _("%d files imported") % count) - except Exception, e: + except Exception as e: messages.error(request, _("ZIP import failed: %s") % str(e)) else: messages.error(request, _("No input file given")) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 62f8f973d..0e25c4dcc 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -12,6 +12,7 @@ from django.dispatch.dispatcher import receiver from django.template.defaultfilters import slugify from django.utils import timezone +from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from feincms import settings @@ -25,12 +26,13 @@ class CategoryManager(models.Manager): """ Simple manager which exists only to supply ``.select_related("parent")`` - on querysets since we can't even __unicode__ efficiently without it. + on querysets since we can't even __str__ efficiently without it. """ def get_query_set(self): return super(CategoryManager, self).get_query_set().select_related("parent") # ------------------------------------------------------------------------ +@python_2_unicode_compatible class Category(models.Model): """ These categories are meant primarily for organizing media files in the @@ -51,7 +53,7 @@ class Meta: objects = CategoryManager() - def __unicode__(self): + def __str__(self): if self.parent_id: return u'%s - %s' % (self.parent.title, self.title) @@ -75,6 +77,7 @@ def path(self): return ' - '.join((f.title for f in self.path_list())) # ------------------------------------------------------------------------ +@python_2_unicode_compatible class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): """ Abstract media file class. Includes the :class:`feincms.models.ExtensionsMixin` @@ -126,7 +129,7 @@ def __init__(self, *args, **kwargs): if self.file: self._original_file_name = self.file.name - def __unicode__(self): + def __str__(self): trans = None try: @@ -137,7 +140,7 @@ def __unicode__(self): pass if trans: - trans = unicode(trans) + trans = u'%s' % trans if trans.strip(): return trans return os.path.basename(self.file.name) @@ -172,7 +175,7 @@ def save(self, *args, **kwargs): if self.file: try: self.file_size = self.file.size - except (OSError, IOError, ValueError), e: + except (OSError, IOError, ValueError) as e: logger.error("Unable to read file size for %s: %s" % (self, e)) super(MediaFileBase, self).save(*args, **kwargs) @@ -193,7 +196,7 @@ def delete_mediafile(self, name=None): name = self.file.name try: self.file.storage.delete(name) - except Exception, e: + except Exception as e: logger.warn("Cannot delete media file %s: %s" % (name, e)) # ------------------------------------------------------------------------ @@ -223,6 +226,7 @@ def _mediafile_post_delete(sender, instance, **kwargs): logger.info("Deleted mediafile %d (%s)" % (instance.id, instance.file.name)) # ------------------------------------------------------------------------ +@python_2_unicode_compatible class MediaFileTranslation(Translation(MediaFile)): """ Translated media file caption and description. @@ -236,7 +240,7 @@ class Meta: verbose_name_plural = _('media file translations') unique_together = ('parent', 'language_code') - def __unicode__(self): + def __str__(self): return self.caption #------------------------------------------------------------------------- diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index a17f3a20b..509fd8bf5 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -138,7 +138,7 @@ def run_request_processors(self): if not getattr(self.object, 'request_processors', None): return - for fn in reversed(self.object.request_processors.values()): + for fn in reversed(list(self.object.request_processors.values())): r = fn(self.object, self.request) if r: return r @@ -176,7 +176,7 @@ def process_content_types(self): successful = r elif r: return r - except Http404, e: + except Http404 as e: http404 = e if not successful: diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 4f04fa684..551a085f5 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -8,6 +8,7 @@ """ from django.db import models +from django.utils import six from django.utils.translation import ugettext_lazy as _ from feincms import extensions @@ -71,14 +72,13 @@ def short_title(self): return shorten_string(self.title) -class NavigationExtension(object): +class NavigationExtension(six.with_metaclass(TypeRegistryMetaClass)): """ Base class for all navigation extensions. The name attribute is shown to the website administrator. """ - __metaclass__ = TypeRegistryMetaClass name = _('navigation extension') def children(self, page, **kwargs): diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 2b337b90c..8e48367a1 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -11,6 +11,7 @@ from django.db.models import Q, signals from django.db.models.loading import get_model from django.http import Http404 +from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from django.db.transaction import commit_on_success @@ -156,6 +157,7 @@ class PageManager(BasePageManager): PageManager.add_to_active_filters(Q(active=True)) # ------------------------------------------------------------------------ +@python_2_unicode_compatible class BasePage(create_base_model(MPTTModel), ContentModelMixin): active = models.BooleanField(_('active'), default=True) @@ -184,7 +186,7 @@ class Meta: objects = PageManager() - def __unicode__(self): + def __str__(self): return self.short_title() def is_active(self): @@ -319,7 +321,7 @@ def cache_key(self): Return a string that may be used as cache key for the current page. The cache_key is unique for each content type and content instance. """ - return '-'.join(unicode(fn(self)) for fn in self.cache_key_components) + return '-'.join(str(fn(self)) for fn in self.cache_key_components) def etag(self, request): """ diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index d404e69d6..4a74818a3 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -124,7 +124,7 @@ def _navext_filter(iterable): this_level = getattr(extended, mptt_opts.level_attr, 0) if this_level < level + depth - 1: yield extended - except Exception, e: + except Exception as e: logger.warn("feincms_nav caught exception in navigation extension for page %d: %s", current_navextension_node.id, format_exception(e)) else: current_navextension_node = None @@ -412,7 +412,7 @@ def siblings_along_path_to(page_list, page2): a_page.level == top_level or any((_is_sibling_of(a_page, a) for a in ancestors))] return siblings - except (AttributeError, ValueError), e: + except (AttributeError, ValueError) as e: logger.warn("siblings_along_path_to caught exception: %s", format_exception(e)) return () diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py index 702ad6422..4a0b24664 100644 --- a/feincms/templatetags/feincms_admin_tags.py +++ b/feincms/templatetags/feincms_admin_tags.py @@ -24,7 +24,7 @@ def post_process_fieldsets(fieldset): def _filter_recursive(fields): ret = [] for f in fields: - if hasattr(f, '__iter__'): + if isinstance(f, (list, tuple)): # Several fields on one line sub = _filter_recursive(f) # Only add if there's at least one field left diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 0b6947967..694c23039 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -2,8 +2,9 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from io import BytesIO import re -from cStringIO import StringIO + # Try to import PIL in either of the two ways it can end up installed. try: from PIL import Image @@ -14,10 +15,10 @@ # Django seems to silently swallow the ImportError under certain # circumstances. Raise a generic exception explaining why we are # unable to proceed. - raise Exception, 'FeinCMS requires PIL to be installed' + raise Exception('FeinCMS requires PIL to be installed') from django import template -from django.utils.encoding import force_unicode +from django.utils.encoding import force_text, python_2_unicode_compatible from django.core.files.storage import default_storage from django.core.files.base import ContentFile @@ -27,6 +28,7 @@ register = template.Library() +@python_2_unicode_compatible class Thumbnailer(object): THUMBNAIL_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)$') MARKER = '_thumb_' @@ -39,7 +41,7 @@ def __init__(self, filename, size='200x200'): def url(self): return unicode(self) - def __unicode__(self): + def __str__(self): match = self.THUMBNAIL_SIZE_RE.match(self.size) if not (self.filename and match): return u'' @@ -56,7 +58,7 @@ def __unicode__(self): if hasattr(self.filename, 'name'): filename = self.filename.name else: - filename = force_unicode(self.filename) + filename = force_text(self.filename) # defining the filename and the miniature filename try: @@ -96,14 +98,14 @@ def __unicode__(self): def generate(self, storage, original, size, miniature): try: - image = Image.open(StringIO(storage.open(original).read())) + image = Image.open(BytesIO(storage.open(original).read())) # defining the size w, h = int(size['w']), int(size['h']) format = image.format # Save format for the save() call later image.thumbnail([w, h], Image.ANTIALIAS) - buf = StringIO() + buf = BytesIO() if image.mode not in ('RGBA', 'RGB', 'L'): image = image.convert('RGBA') image.save(buf, @@ -129,7 +131,7 @@ class CropscaleThumbnailer(Thumbnailer): def generate(self, storage, original, size, miniature): try: - image = Image.open(StringIO(storage.open(original).read())) + image = Image.open(BytesIO(storage.open(original).read())) except: # PIL raises a plethora of Exceptions if reading the image # is not possible. Since we cannot be sure what Exception will @@ -165,7 +167,7 @@ def generate(self, storage, original, size, miniature): image = image.crop((x_offset, y_offset, x_offset+int(crop_width), y_offset+int(crop_height))) image = image.resize((dst_width, dst_height), Image.ANTIALIAS) - buf = StringIO() + buf = BytesIO() if image.mode not in ('RGBA', 'RGB', 'L'): image = image.convert('RGBA') image.save(buf, diff --git a/feincms/templatetags/fragment_tags.py b/feincms/templatetags/fragment_tags.py index 7a126805e..2b01b6774 100644 --- a/feincms/templatetags/fragment_tags.py +++ b/feincms/templatetags/fragment_tags.py @@ -92,7 +92,8 @@ def get_fragment(parser, token): return GetFragmentNode(fragments[1], fragments[2]) elif len(fragments) == 5 and fragments[3] == 'as': return GetFragmentNode(fragments[1], fragments[2], fragments[4]) - raise template.TemplateSyntaxError, 'Invalid syntax for get_fragment: %s' % token.contents + raise template.TemplateSyntaxError( + 'Invalid syntax for get_fragment: %s' % token.contents) @register.filter diff --git a/feincms/translations.py b/feincms/translations.py index d88ed5dbe..ee12b92d8 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -107,7 +107,7 @@ def _transform(qs): if not instance_dict: return - candidates = instance_dict.values()[0].translations.model._default_manager.all() + candidates = list(instance_dict.values())[0].translations.model._default_manager.all() if instance_dict: _process(candidates, instance_dict, lang_, 'iexact') @@ -186,11 +186,11 @@ def get_translation_cache_key(self, language_code=None): if not language_code: language_code = translation.get_language() return (('FEINCMS:%d:XLATION:' % getattr(settings, 'SITE_ID', 0)) + - '-'.join(['%s' % s for s in + '-'.join(['%s' % s for s in ( self._meta.db_table, self.id, language_code, - ])) + )])) def get_translation(self, language_code=None): if not language_code: @@ -224,14 +224,14 @@ def translation(self): def available_translations(self): return self.translations.values_list('language_code', flat=True) - def __unicode__(self): + def __str__(self): try: translation = self.translation except ObjectDoesNotExist: return self.__class__.__name__ if translation: - return unicode(translation) + return u'%s' % translation return self.__class__.__name__ diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 1744cd83d..ad56ac9ae 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import division + try: from hashlib import md5 except ImportError: @@ -11,6 +13,7 @@ from django.core.exceptions import ImproperlyConfigured from django.db.models import AutoField from django.db.models import get_model +from django.utils import six from django.utils.importlib import import_module from feincms import settings @@ -19,7 +22,7 @@ def get_object(path, fail_silently=False): # Return early if path isn't a string (might already be an callable or # a class or whatever) - if not isinstance(path, basestring): + if not isinstance(path, six.string_types): # XXX bytes? return path try: @@ -62,26 +65,11 @@ def shorten_string(str, max_length=50, ellipsis=u' … '): Shorten a string for display, truncate it intelligently when too long. Try to cut it in 2/3 + ellipsis + 1/3 of the original title. Also try to cut the first part off at a white space boundary instead of in mid-word. - - >>> s = shorten_string("Der Wolf und die Grossmutter assen im Wald zu mittag", 15, ellipsis="_") - >>> s - 'Der Wolf und_ag' - >>> len(s) - 15 - - >>> s = shorten_string(u"Haenschen-Klein, ging allein, in den tiefen Wald hinein", 15) - >>> s - u'Haenschen \u2026 ein' - >>> len(s) - 15 - - >>> shorten_string(u"Badgerbadgerbadgerbadgerbadger", 10, ellipsis="-") - u'Badger-ger' """ if len(str) >= max_length: first_part = int(max_length * 0.6) - next_space = str[first_part:(max_length / 2 - first_part)].find(' ') + next_space = str[first_part:(max_length // 2 - first_part)].find(' ') if next_space >= 0 and first_part + next_space + len(ellipsis) < max_length: first_part += next_space return str[:first_part] + ellipsis + str[-(max_length - first_part - len(ellipsis)):] @@ -122,7 +110,7 @@ def get_singleton(template_key, cls=None, raise_exception=True): raise ImproperlyConfigured(u'Cannot load model "%s"' % cls) try: assert model._feincms_templates[template_key].singleton - except AttributeError, e: + except AttributeError as e: raise ImproperlyConfigured( u'%r does not seem to be a valid FeinCMS base class (%r)' % ( model, diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index 4b8d1c841..24f266f56 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -41,7 +41,9 @@ def _func(parser, token): tag_name, of_, in_var_name = token.contents.split() args = '' except ValueError: - raise template.TemplateSyntaxError, 'Invalid syntax for %s node: %s' % (cls.__name__, token.contents) + raise template.TemplateSyntaxError( + 'Invalid syntax for %s node: %s' % ( + cls.__name__, token.contents)) return cls(tag_name, in_var_name, args) @@ -71,7 +73,9 @@ def _func(parser, token): tag_name, of_, in_var_name, as_, var_name = token.contents.split() args = '' except ValueError: - raise template.TemplateSyntaxError, 'Invalid syntax for %s node: %s' % (cls.__name__, token.contents) + raise template.TemplateSyntaxError( + 'Invalid syntax for %s node: %s' % ( + cls.__name__, token.contents)) return cls(tag_name, in_var_name, var_name, args) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 0197e9cb4..85443a61c 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -24,7 +24,7 @@ def get_object(self): def dispatch(self, request, *args, **kwargs): try: return super(Handler, self).dispatch(request, *args, **kwargs) - except Http404, e: + except Http404 as e: if settings.FEINCMS_CMS_404_PAGE: try: request.original_path_info = request.path_info diff --git a/tests/testapp/models.py b/tests/testapp/models.py index c72845276..1fcc9af10 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -1,5 +1,6 @@ from django import forms from django.db import models +from django.utils.encoding import python_2_unicode_compatible from django.utils.text import capfirst from django.utils.translation import ugettext_lazy as _ @@ -83,6 +84,7 @@ def children(self, page, **kwargs): ) +@python_2_unicode_compatible class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() @@ -94,7 +96,7 @@ class Meta: verbose_name = 'category' verbose_name_plural = 'categories' - def __unicode__(self): + def __str__(self): return self.name @@ -102,4 +104,3 @@ def __unicode__(self): Entry.add_to_class('categories', models.ManyToManyField(Category, blank=True, null=True)) EntryAdmin.list_filter += ('categories',) - diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 948a9b73c..c27ab1fc0 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -56,8 +56,8 @@ def test_02_rsscontent_creation(self): # the tests run faster. _orig_parse = feedparser.parse def _new_parse(link): - return _orig_parse( - open(os.path.join(os.path.dirname(__file__), 'yahoo.rss'))) + return _orig_parse(open( + os.path.join(os.path.dirname(__file__), 'yahoo.rss'), 'rb')) feedparser.parse = _new_parse type = ExampleCMSBase.create_content_type(RSSContent) diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 5fc28873c..8dccb7014 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -67,8 +67,8 @@ def testPage(self): page = Page() self.assertTrue(hasattr(page, 'language')) self.assertTrue(hasattr(page, 'translation_of')) - self.assertEquals(self.page_de.translation_of, self.page_en) - self.assertEquals(self.page_de.original_translation, self.page_en) + self.assertEqual(self.page_de.translation_of, self.page_en) + self.assertEqual(self.page_de.original_translation, self.page_en) # TODO: add request tests # with translation.override('de'): \ No newline at end of file diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 0cae626f1..7190897fd 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -22,6 +22,7 @@ from django.template.defaultfilters import slugify from django.test import TestCase from django.utils import timezone +from django.utils.encoding import force_text from feincms import settings as feincms_settings from feincms.content.application.models import _empty_reverse_cache, app_reverse @@ -156,7 +157,7 @@ def create_default_page_set(self): def is_published(self, url, should_be=True): try: self.client.get(url) - except TemplateDoesNotExist, e: + except TemplateDoesNotExist as e: if should_be: if e.args != ('feincms_base.html',): raise @@ -207,7 +208,8 @@ def test_04_add_child(self): page1.active = True page1.save() - self.assertEqual(len(self.client.get('/admin/page/page/').content.split('checked="checked"')), 4) + content = self.client.get('/admin/page/page/').content.decode('utf-8') + self.assertEqual(len(content.split('checked="checked"')), 4) def test_05_override_url(self): self.create_default_page_set() @@ -400,7 +402,7 @@ def test_09_pagecontent(self): self.assertEqual(len(page2.content.all_of_type(RawContent)), 1) self.assertEqual(page2.content.main[0].__class__.__name__, 'RawContent') - self.assertEqual(unicode(page2.content.main[0]), + self.assertEqual(force_text(page2.content.main[0]), u'RawContent, region=main, ordering=0>') self.assertEqual(len(page2.content.main), 1) @@ -423,8 +425,8 @@ def test_10_mediafile_and_imagecontent(self): category = Category.objects.create(title='Category', parent=None) category2 = Category.objects.create(title='Something', parent=category) - self.assertEqual(unicode(category2), 'Category - Something') - self.assertEqual(unicode(category), 'Category') + self.assertEqual(force_text(category2), 'Category - Something') + self.assertEqual(force_text(category), 'Category') mediafile = MediaFile.objects.create(file='somefile.jpg') mediafile.categories = [category] @@ -434,20 +436,20 @@ def test_10_mediafile_and_imagecontent(self): type='default', ordering=1) - self.assertEqual(unicode(mediafile), 'somefile.jpg') + self.assertEqual(force_text(mediafile), 'somefile.jpg') mediafile.translations.create(caption='something', language_code='%s-ha' % short_language_code()) mediafile.purge_translation_cache() - self.assertTrue('something' in unicode(mediafile)) + self.assertTrue('something' in force_text(mediafile)) mf = page.content.main[1].mediafile self.assertEqual(mf.translation.caption, 'something') self.assertEqual(mf.translation.short_language_code(), short_language_code()) self.assertNotEqual(mf.get_absolute_url(), '') - self.assertEqual(unicode(mf), 'something') + self.assertEqual(force_text(mf), 'something') self.assertTrue(mf.type == 'image') self.assertEqual(MediaFile.objects.only_language('de').count(), 0) @@ -652,7 +654,7 @@ def test_15_b_client_frontend_editing(self): response = self.client.get(page.get_absolute_url() + '?frontend_editing=1', follow=True) - self.assertNotIn('class="fe_box"', response.content) + self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) self.assertNotIn('frontend_editing', self.client.cookies) # manually register request processor @@ -664,7 +666,7 @@ def test_15_b_client_frontend_editing(self): '?frontend_editing=1', follow=True) self.assertRedirects(response, page.get_absolute_url()) - self.assertIn('class="fe_box"', response.content) + self.assertIn('class="fe_box"', response.content.decode('utf-8')) self.assertIn('frontend_editing', self.client.cookies) # turn off edit on site @@ -672,7 +674,7 @@ def test_15_b_client_frontend_editing(self): '?frontend_editing=0', follow=True) self.assertRedirects(response, page.get_absolute_url()) - self.assertNotIn('class="fe_box"', response.content) + self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) # anonymous user cannot front edit self.client.logout() @@ -680,7 +682,7 @@ def test_15_b_client_frontend_editing(self): '?frontend_editing=1', follow=True) self.assertRedirects(response, page.get_absolute_url()) - self.assertNotIn('class="fe_box"', response.content) + self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) # cleanup request processor del Page.request_processors['frontend_editing'] @@ -1017,7 +1019,7 @@ def test_20_redirects(self): # page2 has been modified too, but its URL should not have changed try: self.assertRedirects(self.client.get('/blablabla/'), page1.get_absolute_url()) - except TemplateDoesNotExist, e: + except TemplateDoesNotExist as e: # catch the error from rendering page1 if e.args != ('feincms_base.html',): raise @@ -1060,8 +1062,8 @@ def test_22_contactform(self): 'content': 'Hell on earth.', }) - self.assertEquals(len(mail.outbox), 1) - self.assertEquals(mail.outbox[0].subject, 'This is a test. Please calm down') + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].subject, 'This is a test. Please calm down') def test_23_navigation_extension(self): self.create_default_page_set() @@ -1149,7 +1151,7 @@ def test_25_applicationcontent(self): lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) # This should not raise - self.assertEquals(self.client.get(page.get_absolute_url() + 'notexists/').status_code, 404) + self.assertEqual(self.client.get(page.get_absolute_url() + 'notexists/').status_code, 404) self.assertContains(self.client.get(page.get_absolute_url() + 'fragment/'), 'some things') @@ -1285,7 +1287,7 @@ def test_29_medialibrary_admin(self): zf.close() self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/mediafile-bulk-upload/', { - 'data': open('test.zip'), + 'data': open('test.zip', 'rb'), }), '/admin/medialibrary/mediafile/') self.assertEqual(MediaFile.objects.count(), 11, "Upload of media files with ZIP does not work") @@ -1295,7 +1297,7 @@ def test_29_medialibrary_admin(self): 'docs', 'images', 'tree_editor.png') self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/add/', { - 'file': open(path), + 'file': open(path, 'rb'), 'translations-TOTAL_FORMS': 0, 'translations-INITIAL_FORMS': 0, 'translations-MAX_NUM_FORMS': 10, @@ -1376,7 +1378,7 @@ def test_33_preview(self): text='Example content') self.login() - self.assertEquals(self.client.get(page.get_absolute_url()).status_code, 404) + self.assertEqual(self.client.get(page.get_absolute_url()).status_code, 404) self.assertContains(self.client.get('%s_preview/%s/' % (page.get_absolute_url(), page.pk)), 'Example content') @@ -1397,10 +1399,10 @@ def test_34_access(self): self.assertRedirects(r, page.get_absolute_url()) # /something/ should work r = self.client.get(page.override_url) - self.assertEquals(r.status_code, 200) + self.assertEqual(r.status_code, 200) # /foo not existant -> 404 r = self.client.get('/foo/') - self.assertEquals(r.status_code, 404) + self.assertEqual(r.status_code, 404) def test_35_access_with_extra_path(self): self.login() @@ -1410,7 +1412,7 @@ def test_35_access_with_extra_path(self): r = self.client.get('/') self.assertRedirects(r, '/somewhere/') r = self.client.get('/dingdong/') - self.assertEquals(r.status_code, 404) + self.assertEqual(r.status_code, 404) old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True @@ -1418,7 +1420,7 @@ def test_35_access_with_extra_path(self): r = self.client.get('/') self.assertRedirects(r, '/somewhere/') r = self.client.get('/dingdong/') - self.assertEquals(r.status_code, 404) + self.assertEqual(r.status_code, 404) feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index ef3afe8b3..6cbebf050 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -6,6 +6,7 @@ from django.contrib.auth.models import User from django.test import TestCase +from django.utils.encoding import force_text import feincms @@ -16,7 +17,7 @@ from feincms.module.blog.models import Entry from feincms.module.page import processors from feincms.module.page.models import Page -from feincms.utils import collect_dict_values, get_object +from feincms.utils import collect_dict_values, get_object, shorten_string # ------------------------------------------------------------------------ class Empty(object): @@ -33,8 +34,6 @@ def test_translation_short_language_code(self): def test_medialibrary_doctests(self): doctest.testmod(feincms.module.medialibrary.models) - def test_utils(self): - doctest.testmod(feincms.utils) class ModelsTest(TestCase): def test_region(self): @@ -48,7 +47,7 @@ def test_region(self): # I'm not sure whether this test tests anything at all self.assertEqual(r.key, t.regions[0].key) - self.assertEqual(unicode(r), 'region title') + self.assertEqual(force_text(r), 'region title') class UtilsTest(TestCase): @@ -62,6 +61,26 @@ def test_collect_dict_values(self): self.assertEqual({'a': [1, 2], 'b': [3]}, collect_dict_values([('a', 1), ('a', 2), ('b', 3)])) + def test_shorten_string(self): + string = shorten_string( + u"Der Wolf und die Grossmutter assen im Wald zu mittag", + 15, ellipsis=u"_") + self.assertEqual(string, u'Der Wolf und_ag') + self.assertEqual(len(string), 15) + + string = shorten_string( + u"Haenschen-Klein, ging allein, in den tiefen Wald hinein", + 15) + self.assertEqual(string, u'Haenschen \u2026 ein') + self.assertEqual(len(string), 15) + + string = shorten_string( + u'Badgerbadgerbadgerbadgerbadger', + 10, ellipsis=u'-') + self.assertEqual(string, u'Badger-ger') + self.assertEqual(len(string), 10) + + class ExampleCMSBase(Base): pass diff --git a/tests/testapp/tests/utils.py b/tests/testapp/tests/utils.py index 80c7a20d1..cfe6204b7 100644 --- a/tests/testapp/tests/utils.py +++ b/tests/testapp/tests/utils.py @@ -31,7 +31,7 @@ def reset_page_db(): cursor = connection.cursor() for sql in sql_list: cursor.execute(sql) - except Exception, e: + except Exception as e: transaction.rollback_unless_managed() raise CommandError("Error: database couldn't be reset: %s" % e) else: diff --git a/tests/tox.ini b/tests/tox.ini index 3a1b115e3..11950d3ab 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -9,6 +9,7 @@ envlist = py26-1.6.X, py27-1.6.X, py27-1.7.X, + py33-1.5.X, [testenv] downloadcache = {toxworkdir}/_download/ @@ -87,3 +88,13 @@ deps = feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 + +[testenv:py33-1.5.X] +basepython = python3.3 +deps = + Django==1.5.4 + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 From ea72e2377d3550273f831713e2a3cae21a188b34 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 30 Sep 2013 13:13:07 +0200 Subject: [PATCH 0745/1590] tox.ini: Also run the PY3 tests with Django 1.6 and 1.7 --- tests/tox.ini | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/tox.ini b/tests/tox.ini index 11950d3ab..9ebbc6093 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -10,6 +10,8 @@ envlist = py27-1.6.X, py27-1.7.X, py33-1.5.X, + py33-1.6.X, + py33-1.7.X, [testenv] downloadcache = {toxworkdir}/_download/ @@ -98,3 +100,23 @@ deps = feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 + +[testenv:py33-1.6.X] +basepython = python3.3 +deps = + --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 + +[testenv:py33-1.7.X] +basepython = python3.3 +deps = + --editable=git+git://github.com/django/django.git@master#egg=django-dev + django-mptt==0.6.0 + Pillow==2.1.0 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 From b2a770ce69f74902d1c23e838fa883bd6bd6d5a4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 30 Sep 2013 15:39:52 +0200 Subject: [PATCH 0746/1590] Reorder the envlist in tox.ini --- tests/tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tox.ini b/tests/tox.ini index 9ebbc6093..b1abf4b62 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -3,10 +3,10 @@ setupdir = .. distribute = False envlist = py26-1.4.X, - py27-1.4.X, py26-1.5.X, - py27-1.5.X, py26-1.6.X, + py27-1.4.X, + py27-1.5.X, py27-1.6.X, py27-1.7.X, py33-1.5.X, From d179ce14e8402b2e2336d2e9cf19e6e5ea38a670 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 4 Oct 2013 13:33:16 +0200 Subject: [PATCH 0747/1590] Add a shell script to update tox' Django checkouts --- tests/tox-update-venvs.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 tests/tox-update-venvs.sh diff --git a/tests/tox-update-venvs.sh b/tests/tox-update-venvs.sh new file mode 100755 index 000000000..2fabbab8b --- /dev/null +++ b/tests/tox-update-venvs.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +( + cd .tox/py27-1.6.X + bin/pip install -U --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev +) +( + cd .tox/py27-1.7.X + bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev +) +( + cd .tox/py33-1.6.X + bin/pip install -U --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev +) +( + cd .tox/py33-1.7.X + bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev +) From 848b3e766a4520965ab752dd5aa4bfd23554d062 Mon Sep 17 00:00:00 2001 From: Sander van Leeuwen Date: Sun, 6 Oct 2013 19:15:27 +0200 Subject: [PATCH 0748/1590] fix for issue #466, h2 not shown when dragging --- feincms/static/feincms/item_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index ad670043f..753b8f0be 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -515,7 +515,7 @@ if(!Array.indexOf) { $(".order-machine").sortable({ handle: '.handle', helper: function(event, ui){ - var h2 = $("

").html($(ui.item).find('span.modname').html()); + var h2 = $("

").html($(ui).find('span.modname').html()); return $("
").addClass("helper module").append(h2); }, placeholder: 'highlight', From 2a41a14c238a1e3859e9c879f9261b7b9ef14825 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 7 Oct 2013 15:35:42 +0200 Subject: [PATCH 0749/1590] Fix #445: Signed/unsigned problem with MySQL 5.5 This should work fine as long as page trees aren't nested to several dozens of levels... --- feincms/content/application/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 486a1946a..f0cdcab86 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -143,8 +143,9 @@ def app_reverse(viewname, urlconf, args=None, kwargs=None, prefix=None, ) | tree_contents.filter( parent__lft__lte=proximity_info[2], parent__lft__gte=proximity_info[1], - )).extra({'level_diff':"abs(level-%d)" % proximity_info[3]} - ).order_by('level_diff')[0] + )).extra({ + 'level_diff': "abs(100 + level - %d)" % proximity_info[3] + }).order_by('level_diff')[0] except IndexError: content = tree_contents[0] else: From 47e706903973a56203cb775be5faac99abee11d6 Mon Sep 17 00:00:00 2001 From: Sander van Leeuwen Date: Tue, 8 Oct 2013 11:37:16 +0200 Subject: [PATCH 0750/1590] lowered fading speeds and mouseleave timeout of item-controls --- feincms/static/feincms/item_editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 753b8f0be..9714bdd09 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -105,11 +105,11 @@ if(!Array.indexOf) { var mouseenter_timeout; var mouseleave_timeout; function hide_controls() { - item_controls.find("*").fadeOut(800); + item_controls.find("*").fadeOut(400); is_hidden = true; } function show_controls() { - item_controls.find("*").fadeIn(800); + item_controls.find("*").fadeIn(200); is_hidden = false; } item_controls.unbind('mouseleave'); // Unbind in case it's already been bound. From c797b7894e3d1a56a8f80208537d24ad8fe1dcbb Mon Sep 17 00:00:00 2001 From: Sander van Leeuwen Date: Tue, 8 Oct 2013 11:37:16 +0200 Subject: [PATCH 0751/1590] lowered fading speeds and mouseleave timeout of item-controls --- feincms/static/feincms/item_editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 753b8f0be..9714bdd09 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -105,11 +105,11 @@ if(!Array.indexOf) { var mouseenter_timeout; var mouseleave_timeout; function hide_controls() { - item_controls.find("*").fadeOut(800); + item_controls.find("*").fadeOut(400); is_hidden = true; } function show_controls() { - item_controls.find("*").fadeIn(800); + item_controls.find("*").fadeIn(200); is_hidden = false; } item_controls.unbind('mouseleave'); // Unbind in case it's already been bound. From f4c7eccdf9379dc1cef564c324ed63ff4dd09428 Mon Sep 17 00:00:00 2001 From: Sander van Leeuwen Date: Tue, 8 Oct 2013 11:37:16 +0200 Subject: [PATCH 0752/1590] lowered fading speeds and mouseleave timeout of item-controls --- feincms/static/feincms/item_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 9714bdd09..d677813fe 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -115,7 +115,7 @@ if(!Array.indexOf) { item_controls.unbind('mouseleave'); // Unbind in case it's already been bound. item_controls.mouseleave(function() { clearTimeout(mouseenter_timeout); - mouseleave_timeout = setTimeout(hide_controls, 1000); + mouseleave_timeout = setTimeout(hide_controls, 200); }); item_controls.unbind('mouseenter'); // Unbind in case it's already been bound. item_controls.mouseenter(function() { From bd32216607cca9624379fc835461276a9972d675 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac Date: Wed, 9 Oct 2013 11:59:23 +0200 Subject: [PATCH 0753/1590] Add prefetch_modeladmin_get_queryset function to extensions. --- feincms/extensions.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/feincms/extensions.py b/feincms/extensions.py index 4d1131392..9e484e072 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -4,6 +4,7 @@ import re import warnings +from functools import wraps from django.contrib import admin from django.core.exceptions import ImproperlyConfigured @@ -202,3 +203,20 @@ def add_extension_options(self, *f): # Fall back to first fieldset if second does not exist # XXX This is really messy. self.fieldsets[0][1]['fields'].extend(f) + + +def prefetch_modeladmin_get_queryset(modeladmin, *lookups): + """ + Wraps default modeladmin ``get_queryset`` to prefetch related lookups. + """ + def do_wrap(f): + @wraps(f) + def wrapper(request, *args, **kwargs): + qs = f(request, *args, **kwargs) + qs = qs.prefetch_related(*lookups) + return qs + return wrapper + + # queryset is renamed to get_queryset in Django 1.6 + fn = "get_queryset" if hasattr(modeladmin, "get_queryset") else "queryset" + setattr(modeladmin, fn, do_wrap(getattr(modeladmin, fn))) From f2677c889a6b91bbfcc038f39755da13228b14f4 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac Date: Wed, 9 Oct 2013 12:03:16 +0200 Subject: [PATCH 0754/1590] Optimize translations extension admin with prefetching --- feincms/module/extensions/translations.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index cf4c7fd55..43b1d44dd 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -116,6 +116,7 @@ def get_current_language_code(request): # ------------------------------------------------------------------------ class Extension(extensions.Extension): + def handle_model(self): cls = self.model @@ -163,8 +164,11 @@ def available_translations(self): if is_primary_language(self.language): return self.translations.all() elif self.translation_of: - return [self.translation_of] + list(self.translation_of.translations.exclude( - language=self.language)) + # reuse prefetched queryset, do not filter it + res = [t for t in list(self.translation_of.translations.all()) + if t.language != self.language] + res.insert(0, self.translation_of) + return res else: return [] @@ -186,6 +190,9 @@ def get_translation(self, language): def handle_modeladmin(self, modeladmin): + extensions.prefetch_modeladmin_get_queryset( + modeladmin, 'translation_of__translations', 'translations') + def available_translations_admin(self, page): translations = dict((p.language, p.id) for p in page.available_translations()) From 72a361e071b0cfe49c82e850d51df5bf8e89f9a2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 09:34:46 +0200 Subject: [PATCH 0755/1590] flake8-clean the code, mostly --- feincms/__init__.py | 2 + feincms/admin/filterspecs.py | 21 ++++--- feincms/admin/item_editor.py | 4 ++ feincms/admin/tree_editor.py | 58 ++++++++++------- feincms/content/application/models.py | 17 +++-- feincms/content/comments/models.py | 1 + feincms/content/file/models.py | 2 +- feincms/content/image/models.py | 1 - feincms/content/richtext/models.py | 5 +- feincms/content/section/models.py | 9 ++- feincms/content/template/models.py | 2 +- feincms/contrib/preview/urls.py | 6 +- feincms/contrib/richtext.py | 2 +- feincms/contrib/tagging.py | 7 ++- feincms/default_settings.py | 1 - feincms/extensions.py | 1 - feincms/management/checker.py | 7 +-- .../management/commands/feincms_validate.py | 2 +- feincms/management/commands/rebuild_mptt.py | 1 + .../management/commands/update_rsscontent.py | 1 + feincms/models.py | 5 +- feincms/module/blog/models.py | 2 +- feincms/module/extensions/changedate.py | 13 +++- feincms/module/extensions/ct_tracker.py | 8 ++- feincms/module/extensions/datepublisher.py | 17 +++-- feincms/module/extensions/featured.py | 1 + feincms/module/extensions/seo.py | 1 + feincms/module/extensions/translations.py | 13 +++- feincms/module/medialibrary/fields.py | 5 +- feincms/module/medialibrary/forms.py | 9 ++- feincms/module/medialibrary/modeladmins.py | 62 ++++++++++--------- feincms/module/medialibrary/models.py | 20 +++--- feincms/module/medialibrary/thumbnail.py | 2 + feincms/module/medialibrary/zip.py | 38 ++++++++---- feincms/module/mixins.py | 2 + feincms/module/page/__init__.py | 1 - feincms/module/page/extensions/excerpt.py | 1 + feincms/module/page/extensions/navigation.py | 1 - .../module/page/extensions/relatedpages.py | 7 +-- feincms/module/page/extensions/sites.py | 9 ++- feincms/module/page/extensions/titles.py | 1 + feincms/module/page/forms.py | 12 ++-- feincms/module/page/modeladmins.py | 12 ++-- feincms/module/page/models.py | 29 ++++----- feincms/module/page/processors.py | 3 +- feincms/module/page/sitemap.py | 17 ++--- .../page/templatetags/feincms_page_tags.py | 42 +++++++++---- feincms/signals.py | 2 +- .../templatetags/applicationcontent_tags.py | 3 +- feincms/templatetags/feincms_tags.py | 7 ++- feincms/templatetags/feincms_thumbnail.py | 10 ++- feincms/templatetags/fragment_tags.py | 3 +- feincms/translations.py | 1 - feincms/urls.py | 2 +- feincms/utils/__init__.py | 22 ++++--- feincms/utils/html/tidy.py | 20 +++--- feincms/utils/queryset_transform.py | 3 +- feincms/utils/templatetags.py | 5 ++ feincms/views/cbv/views.py | 2 +- feincms/views/decorators.py | 7 +-- setup.cfg | 3 + 61 files changed, 346 insertions(+), 227 deletions(-) create mode 100644 setup.cfg diff --git a/feincms/__init__.py b/feincms/__init__.py index 919571ee4..33f29e385 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -23,6 +23,8 @@ def __getattr__(self, attr): COMPLETELY_LOADED = False + + def ensure_completely_loaded(force=False): """ This method ensures all models are completely loaded diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index c845bdf17..e1d698454 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -9,6 +9,8 @@ from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ +from feincms.utils import shorten_string + class ParentFieldListFilter(ChoicesFieldListFilter): """ @@ -20,8 +22,6 @@ class ParentFieldListFilter(ChoicesFieldListFilter): """ def __init__(self, f, request, params, model, model_admin, field_path=None): - from feincms.utils import shorten_string - super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin, field_path) parent_ids = model.objects.exclude(parent=None).values_list("parent__id", flat=True).order_by("parent__id").distinct() @@ -30,21 +30,22 @@ def __init__(self, f, request, params, model, model_admin, field_path=None): def choices(self, cl): yield { - 'selected': self.lookup_val is None, + 'selected': self.lookup_val is None, 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), - 'display': _('All') + 'display': _('All') } for pk, title in self.lookup_choices: yield { - 'selected': pk == int(self.lookup_val or '0'), + 'selected': pk == int(self.lookup_val or '0'), 'query_string': cl.get_query_string({self.lookup_kwarg: pk}), - 'display': mark_safe(smart_unicode(title)) + 'display': mark_safe(smart_unicode(title)) } def title(self): return _('Parent') + class CategoryFieldListFilter(ChoicesFieldListFilter): """ Customization of ChoicesFilterSpec which sorts in the user-expected format @@ -65,16 +66,16 @@ def __init__(self, f, request, params, model, model_admin, field_path=None): def choices(self, cl): yield { - 'selected': self.lookup_val is None, + 'selected': self.lookup_val is None, 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), - 'display': _('All') + 'display': _('All') } for pk, title in self.lookup_choices: yield { - 'selected': pk == int(self.lookup_val or '0'), + 'selected': pk == int(self.lookup_val or '0'), 'query_string': cl.get_query_string({self.lookup_kwarg: pk}), - 'display': mark_safe(smart_unicode(title)) + 'display': mark_safe(smart_unicode(title)) } def title(self): diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 4a3f2eed1..09d251e14 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -22,6 +22,7 @@ from feincms.extensions import ExtensionModelAdmin from feincms.signals import itemeditor_post_save_related + # ------------------------------------------------------------------------ FRONTEND_EDITING_MATCHER = re.compile(r'(\d+)\|(\w+)\|(\d+)') FEINCMS_CONTENT_FIELDSET_NAME = 'FEINCMS_CONTENT' @@ -29,6 +30,7 @@ logger = logging.getLogger(__name__) + # ------------------------------------------------------------------------ class ItemEditorForm(forms.ModelForm): """ @@ -39,6 +41,7 @@ class ItemEditorForm(forms.ModelForm): region = forms.CharField(widget=forms.HiddenInput()) ordering = forms.IntegerField(widget=forms.HiddenInput()) + # ------------------------------------------------------------------------ class FeinCMSInline(InlineModelAdmin): """ @@ -50,6 +53,7 @@ class FeinCMSInline(InlineModelAdmin): fk_name = 'parent' template = 'admin/feincms/content_inline.html' + # ------------------------------------------------------------------------ class ItemEditor(ExtensionModelAdmin): """ diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 6e81629a4..c2cc26f4e 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -6,10 +6,8 @@ import json import logging -from django.contrib import admin from django.contrib.admin.views import main from django.contrib.admin.actions import delete_selected -from django.db import router from django.contrib.staticfiles.templatetags.staticfiles import static from django.db.models import Q from django.http import (HttpResponse, HttpResponseBadRequest, @@ -25,8 +23,10 @@ from feincms import settings from feincms.extensions import ExtensionModelAdmin + logger = logging.getLogger(__name__) + # ------------------------------------------------------------------------ def django_boolean_icon(field_val, alt_text=None, title=None): """ @@ -34,7 +34,7 @@ def django_boolean_icon(field_val, alt_text=None, title=None): """ # Origin: contrib/admin/templatetags/admin_list.py - BOOLEAN_MAPPING = { True: 'yes', False: 'no', None: 'unknown' } + BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'} alt_text = alt_text or BOOLEAN_MAPPING[field_val] if title is not None: title = 'title="%s" ' % title @@ -57,7 +57,7 @@ def _build_tree_structure(cls): ... } """ - all_nodes = { } + all_nodes = {} mptt_opts = cls._mptt_meta @@ -96,21 +96,22 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): text = u' (%s)' % text if override is not None: - a = [ django_boolean_icon(override, text), text ] + a = [django_boolean_icon(override, text), text] else: value = getattr(item, attr) a = [ - '', - text, + '', + text, ] - a.insert(0, '
' % ( attr, item.pk )) + a.insert(0, '
' % (attr, item.pk)) a.append('
') return u''.join(a) + # ------------------------------------------------------------------------ def ajax_editable_boolean(attr, short_description): """ @@ -162,7 +163,7 @@ def get_results(self, request): )] if clauses: queryset = self.model._default_manager.filter( - reduce(lambda p, q: p|q, clauses)) + reduce(lambda p, q: p | q, clauses)) if hasattr(self, 'queryset'): self.queryset = queryset @@ -175,9 +176,13 @@ def get_results(self, request): # Pre-process permissions because we still have the request here, # which is not passed in later stages in the tree editor for item in self.result_list: - item.feincms_changeable = self.model_admin.has_change_permission(request, item) - item.feincms_addable = (item.feincms_changeable and - self.model_admin.has_add_permission(request, item)) + item.feincms_changeable = self.model_admin.has_change_permission( + request, item) + + item.feincms_addable = ( + item.feincms_changeable + and self.model_admin.has_add_permission(request, item)) + # ------------------------------------------------------------------------ class TreeEditor(ExtensionModelAdmin): @@ -214,7 +219,7 @@ def __init__(self, *args, **kwargs): 'admin/feincms/tree_editor.html', ] self.object_change_permission = opts.app_label + '.' + opts.get_change_permission() - self.object_add_permission = opts.app_label + '.' + opts.get_add_permission() + self.object_add_permission = opts.app_label + '.' + opts.get_add_permission() self.object_delete_permission = opts.app_label + '.' + opts.get_delete_permission() def changeable(self, item): @@ -233,17 +238,21 @@ def indented_short_title(self, item): url = None if url: - r = '' % ( - url, - item.pk - ) + r = ( + '') % (url, item.pk) changeable_class = '' if not self.changeable(item): changeable_class = ' tree-item-not-editable' - r += '  ' % ( - item.pk, changeable_class, 14+getattr(item, mptt_opts.level_attr)*18) + r += ( + '  ') % ( + item.pk, + changeable_class, + 14 + getattr(item, mptt_opts.level_attr) * 18) + # r += '' if hasattr(item, 'short_title') and callable(item.short_title): r += escape(item.short_title()) @@ -323,7 +332,7 @@ def _toggle_boolean(self, request): new_state = not getattr(obj, attr) logger.info("Toggle %s on #%d %s to %s by \"%s\"", - attr, obj.pk, obj, "on" if new_state else "off", request.user) + attr, obj.pk, obj, "on" if new_state else "off", request.user) try: before_data = self._ajax_editable_booleans[attr](self, obj) @@ -331,7 +340,8 @@ def _toggle_boolean(self, request): setattr(obj, attr, new_state) obj.save() - self._refresh_changelist_caches() # ???: Perhaps better a post_save signal? + # ???: Perhaps better a post_save signal? + self._refresh_changelist_caches() # Construct html snippets to send back to client for status update data = self._ajax_editable_booleans[attr](self, obj) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 409dabc9e..48b856a43 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -6,7 +6,6 @@ from time import mktime import re -from django.core import urlresolvers from django.core.urlresolvers import Resolver404, resolve, reverse, NoReverseMatch from django.db import models from django.db.models import signals @@ -15,7 +14,6 @@ from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from feincms import settings from feincms.admin.item_editor import ItemEditorForm from feincms.contrib.fields import JSONField from feincms.utils import get_object @@ -132,7 +130,7 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, cache_key = 'tree' # just one match within the tree, use it content = tree_contents[0] - else: # len(tree_contents) > 1 + else: # len(tree_contents) > 1 cache_key = 'all' try: # select all ancestors and descendants and get the one with @@ -240,9 +238,9 @@ def initialize_type(cls, APPLICATIONS): app_conf = {} cls.ALL_APPS_CONFIG[urls] = { - "urls": urls, - "name": name, - "config": app_conf + "urls": urls, + "name": name, + "config": app_conf } cls.add_to_class('urlconf_path', @@ -251,11 +249,12 @@ def initialize_type(cls, APPLICATIONS): ) class ApplicationContentItemEditorForm(ItemEditorForm): - app_config = {} + app_config = {} custom_fields = {} def __init__(self, *args, **kwargs): - super(ApplicationContentItemEditorForm, self).__init__(*args, **kwargs) + super(ApplicationContentItemEditorForm, self).__init__( + *args, **kwargs) instance = kwargs.get("instance", None) @@ -386,7 +385,7 @@ def process(self, request, **kw): else: self.rendered_result = mark_safe(output) - return True # successful + return True # successful def send_directly(self, request, response): mimetype = response.get('Content-Type', 'text/plain') diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index 40702e0ef..e8f049234 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -19,6 +19,7 @@ from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ + # ------------------------------------------------------------------------ class CommentsContent(models.Model): comments_enabled = models.BooleanField(_('enabled'), default=True, help_text=_('New comments may be added')) diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index 5b8361378..9f2be2c9a 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -11,6 +11,7 @@ from feincms import settings + class FileContent(models.Model): # You should probably use # `feincms.content.medialibrary.models.MediaFileContent` instead. @@ -30,4 +31,3 @@ def render(self, **kwargs): 'content/file/%s.html' % self.region, 'content/file/default.html', ], {'content': self}, context_instance=kwargs.get('context')) - diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index 6c998115f..360965c1a 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -5,7 +5,6 @@ import os -from django.core.exceptions import ImproperlyConfigured from django.db import models from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 8680646b5..7208ea19e 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -58,6 +58,7 @@ def clean(self): return cleaned_data + class RichTextContent(models.Model): """ Rich text content. Uses TinyMCE by default, but can be configured to do @@ -75,7 +76,7 @@ class RichTextContent(models.Model): lambda x: settings.FEINCMS_RICHTEXT_INIT_CONTEXT, ) feincms_item_editor_includes = { - 'head': [ settings.FEINCMS_RICHTEXT_INIT_TEMPLATE ], + 'head': [settings.FEINCMS_RICHTEXT_INIT_TEMPLATE], } text = RichTextField(_('text'), blank=True) @@ -87,7 +88,7 @@ class Meta: def render(self, **kwargs): return render_to_string('content/richtext/default.html', - { 'content': self }, context_instance=kwargs.get('context')) + {'content': self}, context_instance=kwargs.get('context')) def save(self, *args, **kwargs): # TODO: Move this to the form? diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index eb8312ada..8ff2fd353 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -1,4 +1,3 @@ -from django import forms from django.conf import settings as django_settings from django.contrib import admin from django.core.exceptions import ImproperlyConfigured @@ -44,10 +43,14 @@ class Meta: @classmethod def initialize_type(cls, TYPE_CHOICES=None, cleanse=None): if 'feincms.module.medialibrary' not in django_settings.INSTALLED_APPS: - raise ImproperlyConfigured, 'You have to add \'feincms.module.medialibrary\' to your INSTALLED_APPS before creating a %s' % cls.__name__ + raise ImproperlyConfigured( + 'You have to add \'feincms.module.medialibrary\' to your' + ' INSTALLED_APPS before creating a %s' % cls.__name__) if TYPE_CHOICES is None: - raise ImproperlyConfigured, 'You need to set TYPE_CHOICES when creating a %s' % cls.__name__ + raise ImproperlyConfigured( + 'You need to set TYPE_CHOICES when creating a' + ' %s' % cls.__name__) cls.add_to_class('type', models.CharField(_('type'), max_length=10, choices=TYPE_CHOICES, diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index aa918291e..be79d0fac 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -85,4 +85,4 @@ def render(self, **kwargs): return result - return u'' # Fail? + return u'' diff --git a/feincms/contrib/preview/urls.py b/feincms/contrib/preview/urls.py index bcdc51ac7..a957b5ca3 100644 --- a/feincms/contrib/preview/urls.py +++ b/feincms/contrib/preview/urls.py @@ -1,7 +1,9 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import patterns, url from feincms.contrib.preview.views import PreviewHandler + urlpatterns = patterns('', - url(r'^(.*)/_preview/(\d+)/$', PreviewHandler.as_view(), name='feincms_preview'), + url(r'^(.*)/_preview/(\d+)/$', PreviewHandler.as_view(), + name='feincms_preview'), ) diff --git a/feincms/contrib/richtext.py b/feincms/contrib/richtext.py index 28f017dc3..5e9e05c15 100644 --- a/feincms/contrib/richtext.py +++ b/feincms/contrib/richtext.py @@ -26,7 +26,7 @@ def formfield(self, form_class=RichTextFormField, **kwargs): try: from south.modelsinspector import add_introspection_rules - RichTextField_introspection_rule = ( (RichTextField,), [], {}, ) + RichTextField_introspection_rule = ((RichTextField,), [], {},) add_introspection_rules(rules=[RichTextField_introspection_rule], patterns=["^feincms\.contrib\.richtext"]) diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 19e352d17..d412ce6dd 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -18,6 +18,7 @@ from tagging.fields import TagField from tagging import AlreadyRegistered + # ------------------------------------------------------------------------ def taglist_to_string(taglist): retval = '' @@ -42,10 +43,12 @@ class MyModel(models.Model): """ + class TagSelectFormField(forms.MultipleChoiceField): def clean(self, value): return taglist_to_string(list(value)) + class TagSelectField(TagField): def __init__(self, filter_horizontal=False, *args, **kwargs): super(TagSelectField, self).__init__(*args, **kwargs) @@ -65,9 +68,10 @@ def _render(name, value, attrs=None, *args, **kwargs): return type(widget).render(widget, name, value, attrs, *args, **kwargs) widget.render = _render defaults['widget'] = widget - choices = [ (str(t), str(t)) for t in Tag.objects.all() ] + choices = [(str(t), str(t)) for t in Tag.objects.all()] return TagSelectFormField(choices=choices, required=not self.blank, **defaults) + # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ def pre_save_handler(sender, instance, **kwargs): @@ -80,6 +84,7 @@ def pre_save_handler(sender, instance, **kwargs): taglist = parse_tag_input(instance.tags) instance.tags = taglist_to_string(taglist) + # ------------------------------------------------------------------------ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_field=False, auto_add_admin_field=True): """ diff --git a/feincms/default_settings.py b/feincms/default_settings.py index eec93a866..ae41a036e 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -148,4 +148,3 @@ settings, 'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED', False) # ------------------------------------------------------------------------ - diff --git a/feincms/extensions.py b/feincms/extensions.py index ed8bd62fc..bc6bb085a 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -2,7 +2,6 @@ Base types for extensions refactor """ -import re import warnings from django.contrib import admin diff --git a/feincms/management/checker.py b/feincms/management/checker.py index b52668741..38104cdb3 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -27,7 +27,7 @@ def _fn(sender, **kwargs): cursor = connection.cursor() - existing_columns = [row[0] for row in \ + existing_columns = [row[0] for row in connection.introspection.get_table_description(cursor, cls._meta.db_table)] missing_columns = [] @@ -51,7 +51,6 @@ def _fn(sender, **kwargs): print(style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to' ' find out what the correct column types are. (Or use south, which is what' - ' you should be doing anyway.)\n' % ( - cls._meta.app_label, - ))) + ' you should be doing anyway.)\n' % (cls._meta.app_label))) + return _fn diff --git a/feincms/management/commands/feincms_validate.py b/feincms/management/commands/feincms_validate.py index 3c003b47c..d76d26ff7 100644 --- a/feincms/management/commands/feincms_validate.py +++ b/feincms/management/commands/feincms_validate.py @@ -47,4 +47,4 @@ def validate_content_type(self, model): for base in model.__bases__: if not base._meta.abstract: - print self.style.NOTICE('One of %s bases, %s, is not abstract' % (model, base)) \ No newline at end of file + print self.style.NOTICE('One of %s bases, %s, is not abstract' % (model, base)) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index ddf4a76aa..5442e9f43 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -12,6 +12,7 @@ from feincms.module.page.models import Page + class Command(NoArgsCommand): help = "Run this manually to rebuild your mptt pointers. Only use in emergencies." diff --git a/feincms/management/commands/update_rsscontent.py b/feincms/management/commands/update_rsscontent.py index ee4994a18..78e641174 100644 --- a/feincms/management/commands/update_rsscontent.py +++ b/feincms/management/commands/update_rsscontent.py @@ -11,6 +11,7 @@ from feincms.content.rss.models import RSSContent + class Command(BaseCommand): help = "Run this as a cronjob." diff --git a/feincms/models.py b/feincms/models.py index c93e5c980..c6d82a163 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -173,7 +173,7 @@ def _fetch_content_type_count_helper(self, pk, regions=None): tmpl.append('GROUP BY region') tmpl = u' '.join(tmpl) - sql = ' UNION '.join([tmpl % (idx, cls._meta.db_table, pk)\ + sql = ' UNION '.join([tmpl % (idx, cls._meta.db_table, pk) for idx, cls in enumerate(self.item._feincms_content_types)]) sql = 'SELECT * FROM ( ' + sql + ' ) AS ct ORDER BY ct_idx' @@ -529,12 +529,11 @@ def get_queryset(cls, filter_args): 'FeinCMS auto-generates based on %s.%s. To avoid database' 'errors and import clashes, rename one of these classes.' % (cls.__module__, name, cls.__module__, cls.__name__), - RuntimeWarning) + RuntimeWarning) cls._feincms_content_model = python_2_unicode_compatible( type(name, (models.Model,), attrs)) - # list of concrete content types cls._feincms_content_types = [] diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index e266936c2..a0fd72cb7 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -63,7 +63,7 @@ def get_absolute_url(self): class EntryAdmin(item_editor.ItemEditor): date_hierarchy = 'published_on' list_display = ['__str__', 'published', 'published_on'] - list_filter = ['published',] + list_filter = ['published'] search_fields = ['title', 'slug'] prepopulated_fields = { 'slug': ('title',), diff --git a/feincms/module/extensions/changedate.py b/feincms/module/extensions/changedate.py index ebafcc153..ec2b4d624 100644 --- a/feincms/module/extensions/changedate.py +++ b/feincms/module/extensions/changedate.py @@ -12,6 +12,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ + # ------------------------------------------------------------------------ def pre_save_handler(sender, instance, **kwargs): """ @@ -23,22 +24,28 @@ def pre_save_handler(sender, instance, **kwargs): instance.creation_date = now instance.modification_date = now + # ------------------------------------------------------------------------ def dt_to_utc_timestamp(dt): from time import mktime return int(mktime(dt.timetuple())) + def register(cls, admin_cls): - cls.add_to_class('creation_date', models.DateTimeField(_('creation date'), null=True, editable=False)) - cls.add_to_class('modification_date', models.DateTimeField(_('modification date'), null=True, editable=False)) + cls.add_to_class('creation_date', + models.DateTimeField(_('creation date'), null=True, editable=False)) + cls.add_to_class('modification_date', + models.DateTimeField(_('modification date'), null=True, editable=False)) if hasattr(cls, 'cache_key_components'): - cls.cache_key_components.append(lambda page: page.modification_date and str(dt_to_utc_timestamp(page.modification_date))) + cls.cache_key_components.append( + lambda page: page.modification_date and str(dt_to_utc_timestamp(page.modification_date))) cls.last_modified = lambda p: p.modification_date pre_save.connect(pre_save_handler, sender=cls) + # ------------------------------------------------------------------------ def last_modified_response_processor(page, request, response): from django.utils.http import http_date diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 4c6f7206c..58b35b797 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -82,7 +82,7 @@ def _translation_map(self): dct = ContentType.objects.get_for_model(fct) # Rely on non-negative primary keys - map[-dct.id] = idx # From-inventory map + map[-dct.id] = idx # From-inventory map map[idx] = dct.id # To-inventory map _translation_map_cache[cls] = map @@ -98,7 +98,7 @@ def _from_inventory(self, inventory): return dict((region, [ (pk, map[-ct]) for pk, ct in items - ]) for region, items in inventory.items() if region!='_version_') + ]) for region, items in inventory.items() if region != '_version_') def _to_inventory(self, counts): map = self._translation_map() @@ -109,6 +109,7 @@ def _to_inventory(self, counts): inventory['_version_'] = INVENTORY_VERSION return inventory + # ------------------------------------------------------------------------ def class_prepared_handler(sender, **kwargs): # It might happen under rare circumstances that not all model classes @@ -119,6 +120,7 @@ def class_prepared_handler(sender, **kwargs): _translation_map_cache = {} class_prepared.connect(class_prepared_handler) + # ------------------------------------------------------------------------ def tree_post_save_handler(sender, instance, **kwargs): """ @@ -129,12 +131,14 @@ def tree_post_save_handler(sender, instance, **kwargs): # inheritance has been customized. instance.get_descendants(include_self=True).update(_ct_inventory=None) + # ------------------------------------------------------------------------ def single_pre_save_handler(sender, instance, **kwargs): """Clobber the _ct_inventory attribute of this object""" instance._ct_inventory = None + # ------------------------------------------------------------------------ def register(cls, admin_cls): cls.add_to_class('_ct_inventory', JSONField(_('content types'), editable=False, blank=True, null=True)) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index cec7d7d43..4c35f60a4 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -16,6 +16,7 @@ from django.utils.cache import patch_response_headers from django.utils.translation import ugettext_lazy as _ + # ------------------------------------------------------------------------ def format_date(d, if_none=''): """ @@ -23,15 +24,18 @@ def format_date(d, if_none=''): year. Also return a default value if no date is passed in. """ - if d is None: return if_none + if d is None: + return if_none now = timezone.now() fmt = (d.year == now.year) and '%d.%m' or '%d.%m.%Y' return d.strftime(fmt) + def latest_children(self): return self.get_children().order_by('-publication_date') + # ------------------------------------------------------------------------ def granular_now(n=None): """ @@ -46,6 +50,7 @@ def granular_now(n=None): return timezone.make_aware(datetime(n.year, n.month, n.day, n.hour, (n.minute // 5) * 5), n.tzinfo) + # ------------------------------------------------------------------------ def datepublisher_response_processor(page, request, response): """ @@ -61,15 +66,15 @@ def datepublisher_response_processor(page, request, response): delta = int(delta.days * 86400 + delta.seconds) patch_response_headers(response, delta) + # ------------------------------------------------------------------------ def register(cls, admin_cls): cls.add_to_class('publication_date', - models.DateTimeField(_('publication date'), - default=granular_now)) + models.DateTimeField(_('publication date'), default=granular_now)) cls.add_to_class('publication_end_date', - models.DateTimeField(_('publication end date'), - blank=True, null=True, - help_text=_('Leave empty if the entry should stay active forever.'))) + models.DateTimeField(_('publication end date'), + blank=True, null=True, + help_text=_('Leave empty if the entry should stay active forever.'))) cls.add_to_class('latest_children', latest_children) # Patch in rounding the pub and pub_end dates on save diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index 6d9c511ef..a41e42772 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -5,6 +5,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ + def register(cls, admin_cls): cls.add_to_class('featured', models.BooleanField(_('featured'))) diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index 439cc14be..155991d73 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -5,6 +5,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ + def register(cls, admin_cls): cls.add_to_class('meta_keywords', models.TextField(_('meta keywords'), blank=True, help_text=_('This will be prepended to the default keyword list.'))) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index cf4c7fd55..39d5ee6a2 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -27,9 +27,11 @@ from feincms.translations import is_primary_language from feincms._internal import monkeypatch_method, monkeypatch_property + # ------------------------------------------------------------------------ logger = logging.getLogger(__name__) + # ------------------------------------------------------------------------ def user_has_language_set(request): """ @@ -43,6 +45,7 @@ def user_has_language_set(request): return True return False + # ------------------------------------------------------------------------ def translation_set_language(request, select_language): """ @@ -76,6 +79,7 @@ def translation_set_language(request, select_language): response.set_cookie(django_settings.LANGUAGE_COOKIE_NAME, select_language) return response + # ------------------------------------------------------------------------ def translations_request_processor_explicit(page, request): # If this page is just a redirect, don't do any language specific setup @@ -96,6 +100,7 @@ def translations_request_processor_explicit(page, request): return translation_set_language(request, desired_language) + # ------------------------------------------------------------------------ def translations_request_processor_standard(page, request): # If this page is just a redirect, don't do any language specific setup @@ -107,6 +112,7 @@ def translations_request_processor_standard(page, request): return translation_set_language(request, page.language) + # ------------------------------------------------------------------------ def get_current_language_code(request): language_code = getattr(request, 'LANGUAGE_CODE', None) @@ -114,6 +120,7 @@ def get_current_language_code(request): logger.warning("Could not access request.LANGUAGE_CODE. Is 'django.middleware.locale.LocaleMiddleware' in MIDDLEWARE_CLASSES?") return language_code + # ------------------------------------------------------------------------ class Extension(extensions.Extension): def handle_model(self): @@ -132,12 +139,13 @@ def handle_model(self): if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": cls.register_request_processor(translations_request_processor_explicit, key='translations') - else: # STANDARD + else: # STANDARD cls.register_request_processor(translations_request_processor_standard, key='translations') if hasattr(cls, 'get_redirect_to_target'): original_get_redirect_to_target = cls.get_redirect_to_target + @monkeypatch_method(cls) def get_redirect_to_target(self, request): """ @@ -158,7 +166,7 @@ def get_redirect_to_target(self, request): @monkeypatch_method(cls) def available_translations(self): - if not self.id: # New, unsaved pages have no translations + if not self.id: # New, unsaved pages have no translations return [] if is_primary_language(self.language): return self.translations.all() @@ -217,4 +225,3 @@ def available_translations_admin(self, page): modeladmin.raw_id_fields.append('translation_of') # ------------------------------------------------------------------------ -# ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 109d7ffe2..ae614ea38 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -4,8 +4,6 @@ from __future__ import absolute_import -from os.path import splitext - from django.contrib.admin.widgets import AdminFileWidget from django.contrib.admin.widgets import ForeignKeyRawIdWidget from django.db import models @@ -18,8 +16,10 @@ from .models import MediaFile from .thumbnail import admin_thumbnail + __all__ = ('MediaFileForeignKey', 'ContentWithMediaFile') + # ------------------------------------------------------------------------ class MediaFileForeignKeyRawIdWidget(ForeignKeyRawIdWidget): def __init__(self, original): @@ -62,6 +62,7 @@ class feincms_item_editor_inline(FeinCMSInline): class Meta: abstract = True + # ------------------------------------------------------------------------ class AdminFileWithPreviewWidget(AdminFileWidget): """ diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 2437c08f7..f8759e938 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -15,6 +15,7 @@ from .models import Category, MediaFile from .fields import AdminFileWithPreviewWidget + # ------------------------------------------------------------------------ class MediaCategoryAdminForm(forms.ModelForm): class Meta: @@ -27,15 +28,16 @@ def clean_parent(self): return data - def __init__(self,* args, **kwargs): + def __init__(self, *args, **kwargs): super(MediaCategoryAdminForm, self).__init__(*args, **kwargs) self.fields['parent'].queryset = self.fields['parent'].queryset.exclude(pk=self.instance.pk) + # ------------------------------------------------------------------------ class MediaFileAdminForm(forms.ModelForm): class Meta: model = MediaFile - widgets = { 'file': AdminFileWithPreviewWidget } + widgets = {'file': AdminFileWithPreviewWidget} def __init__(self, *args, **kwargs): super(MediaFileAdminForm, self).__init__(*args, **kwargs) @@ -61,7 +63,8 @@ def clean_file(self): old_base, old_ext = os.path.splitext(self.instance.file.name) if new_ext.lower() != old_ext.lower(): - raise forms.ValidationError(_("Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)") % { 'old_ext': old_ext, 'new_ext': new_ext }) + raise forms.ValidationError( + _("Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)") % {'old_ext': old_ext, 'new_ext': new_ext}) self.instance.original_name = self.instance.file.name diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 6f785a3e2..c5f9396a5 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -18,7 +18,6 @@ from django.shortcuts import render_to_response from django.template.context import RequestContext from django.template.defaultfilters import filesizeformat -from django.utils.encoding import python_2_unicode_compatible from django.utils.safestring import mark_safe from django.utils.translation import ungettext, ugettext_lazy as _ from django.views.decorators.csrf import csrf_protect @@ -30,14 +29,16 @@ from .forms import MediaCategoryAdminForm, MediaFileAdminForm from .thumbnail import admin_thumbnail + # ----------------------------------------------------------------------- class CategoryAdmin(admin.ModelAdmin): form = MediaCategoryAdminForm - list_display = ['path'] - list_filter = ['parent'] - list_per_page = 25 - search_fields = ['title'] - prepopulated_fields = { 'slug': ('title',), } + list_display = ['path'] + list_filter = ['parent'] + list_per_page = 25 + search_fields = ['title'] + prepopulated_fields = {'slug': ('title',)} + #------------------------------------------------------------------------- def assign_category(modeladmin, request, queryset): @@ -56,9 +57,10 @@ class AddCategoryForm(forms.Form): category.mediafile_set.add(mediafile) count += 1 - message = ungettext('Successfully added %(count)d media file to %(category)s.', - 'Successfully added %(count)d media files to %(category)s.', - count) % {'count':count, 'category':category} + message = ungettext( + 'Successfully added %(count)d media file to %(category)s.', + 'Successfully added %(count)d media files to %(category)s.', + count) % {'count': count, 'category': category} modeladmin.message_user(request, message) return HttpResponseRedirect(request.get_full_path()) if 'cancel' in request.POST: @@ -75,8 +77,10 @@ class AddCategoryForm(forms.Form): 'opts': modeladmin.model._meta, }, context_instance=RequestContext(request)) + assign_category.short_description = _('Add selected media files to category') + #------------------------------------------------------------------------- def save_as_zipfile(modeladmin, request, queryset): from .zip import export_zipfile @@ -91,25 +95,27 @@ def save_as_zipfile(modeladmin, request, queryset): return HttpResponseRedirect(os.path.join(django_settings.MEDIA_URL, zip_name)) + save_as_zipfile.short_description = _('Export selected media files as zip file') + # ------------------------------------------------------------------------ class MediaFileAdmin(ExtensionModelAdmin): - form = MediaFileAdminForm + form = MediaFileAdminForm - save_on_top = True - date_hierarchy = 'created' - inlines = [admin_translationinline(MediaFileTranslation)] - list_display = ['admin_thumbnail', '__str__', 'file_info', 'formatted_created'] + save_on_top = True + date_hierarchy = 'created' + inlines = [admin_translationinline(MediaFileTranslation)] + list_display = ['admin_thumbnail', '__str__', 'file_info', 'formatted_created'] list_display_links = ['__str__'] - list_filter = ['type', 'categories'] - list_per_page = 25 - search_fields = ['copyright', 'file', 'translations__caption'] + list_filter = ['type', 'categories'] + list_per_page = 25 + search_fields = ['copyright', 'file', 'translations__caption'] filter_horizontal = ("categories",) - actions = [assign_category, save_as_zipfile] + actions = [assign_category, save_as_zipfile] def get_urls(self): - from django.conf.urls import patterns, include, url + from django.conf.urls import patterns, url urls = super(MediaFileAdmin, self).get_urls() my_urls = patterns('', @@ -132,7 +138,7 @@ def admin_thumbnail(self, obj): """ % { 'url': obj.file.url, - 'image': image,}) + 'image': image}) return '' admin_thumbnail.short_description = _('Preview') admin_thumbnail.allow_tags = True @@ -158,7 +164,7 @@ def file_type(self, obj): try: d = get_image_dimensions(obj.file.file) if d: - t += " %d×%d" % ( d[0], d[1] ) + t += " %d×%d" % (d[0], d[1]) except (IOError, ValueError) as e: t += " (%s)" % e return t @@ -176,13 +182,13 @@ def file_info(self, obj): """ from feincms.utils import shorten_string return u' %s
%s, %s' % ( - obj.id, - obj.file.name, - obj.id, - shorten_string(os.path.basename(obj.file.name), max_length=40), - self.file_type(obj), - self.formatted_file_size(obj), - ) + obj.id, + obj.file.name, + obj.id, + shorten_string(os.path.basename(obj.file.name), max_length=40), + self.file_type(obj), + self.formatted_file_size(obj), + ) file_info.admin_order_field = 'file' file_info.short_description = _('file info') file_info.allow_tags = True diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 0e25c4dcc..ddac544a6 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -22,6 +22,7 @@ from . import logger + # ------------------------------------------------------------------------ class CategoryManager(models.Manager): """ @@ -31,6 +32,7 @@ class CategoryManager(models.Manager): def get_query_set(self): return super(CategoryManager, self).get_query_set().select_related("parent") + # ------------------------------------------------------------------------ @python_2_unicode_compatible class Category(models.Model): @@ -68,7 +70,7 @@ def save(self, *args, **kwargs): def path_list(self): if self.parent is None: - return [ self ] + return [self] p = self.parent.path_list() p.append(self) return p @@ -76,6 +78,7 @@ def path_list(self): def path(self): return ' - '.join((f.title for f in self.path_list())) + # ------------------------------------------------------------------------ @python_2_unicode_compatible class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): @@ -88,7 +91,7 @@ class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): type = models.CharField(_('file type'), max_length=12, editable=False, choices=()) created = models.DateTimeField(_('created'), editable=False, default=timezone.now) copyright = models.CharField(_('copyright'), max_length=200, blank=True) - file_size = models.IntegerField(_("file size"), blank=True, null=True, editable=False) + file_size = models.IntegerField(_("file size"), blank=True, null=True, editable=False) categories = models.ManyToManyField(Category, verbose_name=_('categories'), blank=True, null=True) @@ -102,8 +105,8 @@ class Meta: objects = TranslatedObjectManager() - filetypes = [ ] - filetypes_dict = { } + filetypes = [] + filetypes_dict = {} @classmethod def reconfigure(cls, upload_to=None, storage=None): @@ -120,7 +123,7 @@ def reconfigure(cls, upload_to=None, storage=None): @classmethod def register_filetypes(cls, *types): cls.filetypes[0:0] = types - choices = [ t[0:2] for t in cls.filetypes ] + choices = [t[0:2] for t in cls.filetypes] cls.filetypes_dict = dict(choices) cls._meta.get_field('type').choices[:] = choices @@ -199,6 +202,7 @@ def delete_mediafile(self, name=None): except Exception as e: logger.warn("Cannot delete media file %s: %s" % (name, e)) + # ------------------------------------------------------------------------ MediaFileBase.register_filetypes( # Should we be using imghdr.what instead of extension guessing? @@ -213,18 +217,21 @@ def delete_mediafile(self, name=None): ('doc', _('Microsoft Word'), lambda f: re.compile(r'\.docx?$', re.IGNORECASE).search(f)), ('xls', _('Microsoft Excel'), lambda f: re.compile(r'\.xlsx?$', re.IGNORECASE).search(f)), ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile(r'\.pptx?$', re.IGNORECASE).search(f)), - ('other', _('Binary'), lambda f: True), # Must be last + ('other', _('Binary'), lambda f: True), # Must be last ) + # ------------------------------------------------------------------------ class MediaFile(MediaFileBase): pass + @receiver(post_delete, sender=MediaFile) def _mediafile_post_delete(sender, instance, **kwargs): instance.delete_mediafile() logger.info("Deleted mediafile %d (%s)" % (instance.id, instance.file.name)) + # ------------------------------------------------------------------------ @python_2_unicode_compatible class MediaFileTranslation(Translation(MediaFile)): @@ -244,4 +251,3 @@ def __str__(self): return self.caption #------------------------------------------------------------------------- -#------------------------------------------------------------------------- diff --git a/feincms/module/medialibrary/thumbnail.py b/feincms/module/medialibrary/thumbnail.py index e6660021a..a4cfb560d 100644 --- a/feincms/module/medialibrary/thumbnail.py +++ b/feincms/module/medialibrary/thumbnail.py @@ -11,6 +11,8 @@ def default_admin_thumbnail(mediafile, dimensions='100x100', **kwargs): _cached_thumbnailer = None + + def admin_thumbnail(mediafile, dimensions='100x100'): global _cached_thumbnailer if not _cached_thumbnailer: diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 28b1712af..36598cb75 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -20,9 +20,11 @@ from .models import Category, MediaFile, MediaFileTranslation + # ------------------------------------------------------------------------ export_magic = 'feincms-export-01' + # ------------------------------------------------------------------------ def import_zipfile(category_id, overwrite, data): """ @@ -100,8 +102,8 @@ def import_zipfile(category_id, overwrite, data): for tr in info['translations']: found_metadata = True mt, mt_created = MediaFileTranslation.objects.get_or_create(parent=mf, language_code=tr['lang']) - mt.caption = tr['caption'] - mt.description = tr.get('description', None) + mt.caption = tr['caption'] + mt.description = tr.get('description', None) mt.save() # Add categories @@ -111,7 +113,7 @@ def import_zipfile(category_id, overwrite, data): if not found_metadata: mt = MediaFileTranslation() - mt.parent = mf + mt.parent = mf mt.caption = fname.replace('_', ' ') mt.save() @@ -122,9 +124,10 @@ def import_zipfile(category_id, overwrite, data): return count + # ------------------------------------------------------------------------ def export_zipfile(site, queryset): - now = timezone.now() + now = timezone.now() zip_name = "export_%s_%04d%02d%02d.zip" % (slugify(site.domain), now.year, now.month, now.day) zip_data = open(os.path.join(django_settings.MEDIA_ROOT, zip_name), "w") @@ -136,23 +139,34 @@ def export_zipfile(site, queryset): for cat in mf.categories.all(): used_categories.update(cat.path_list()) - info = { 'export_magic': export_magic, - 'categories': [ { 'id': cat.id, 'title': cat.title, 'slug': cat.slug, 'parent': cat.parent_id or 0, 'level': len(cat.path_list()) } for cat in used_categories ], - } + info = { + 'export_magic': export_magic, + 'categories': [{ + 'id': cat.id, + 'title': cat.title, + 'slug': cat.slug, + 'parent': cat.parent_id or 0, + 'level': len(cat.path_list()), + } for cat in used_categories], + } zip_file.comment = json.dumps(info) for mf in queryset: ctime = time.localtime(os.stat(mf.file.path).st_ctime) info = json.dumps({ 'copyright': mf.copyright, - 'categories': [ cat.id for cat in mf.categories.all() ], - 'translations': [ - { 'lang': t.language_code, 'caption': t.caption, 'description': t.description } - for t in mf.translations.all() ], + 'categories': [cat.id for cat in mf.categories.all()], + 'translations': [{ + 'lang': t.language_code, + 'caption': t.caption, + 'description': t.description, + } for t in mf.translations.all()], }) with open(mf.file.path, "r") as file_data: - zip_info = zipfile.ZipInfo(filename=mf.file.name, date_time=(ctime.tm_year, ctime.tm_mon, ctime.tm_mday, ctime.tm_hour, ctime.tm_min, ctime.tm_sec)) + zip_info = zipfile.ZipInfo( + filename=mf.file.name, + date_time=(ctime.tm_year, ctime.tm_mon, ctime.tm_mday, ctime.tm_hour, ctime.tm_min, ctime.tm_sec)) zip_info.comment = info zip_file.writestr(zip_info, file_data.read()) diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 509fd8bf5..b397ed4fc 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -8,6 +8,7 @@ from feincms import settings from feincms.views.decorators import standalone + class ContentModelMixin(object): """ Mixin for ``feincms.models.Base`` subclasses which need need some degree of @@ -57,6 +58,7 @@ def module_name(self): "See app_label" return self.__class__.__name__.lower() + class ContentObjectMixin(TemplateResponseMixin): """ Mixin for Django's class based views which knows how to handle diff --git a/feincms/module/page/__init__.py b/feincms/module/page/__init__.py index 8b1378917..e69de29bb 100644 --- a/feincms/module/page/__init__.py +++ b/feincms/module/page/__init__.py @@ -1 +0,0 @@ - diff --git a/feincms/module/page/extensions/excerpt.py b/feincms/module/page/extensions/excerpt.py index be987ffd4..0350e5076 100644 --- a/feincms/module/page/extensions/excerpt.py +++ b/feincms/module/page/extensions/excerpt.py @@ -5,6 +5,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ + def register(cls, admin_cls): cls.add_to_class('excerpt', models.TextField(_('excerpt'), blank=True, help_text=_('Add a brief excerpt summarizing the content of this page.'))) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 551a085f5..3d4aa57f5 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -120,7 +120,6 @@ def extended_navigation(self, **kwargs): return cls().children(self, **kwargs) - def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Navigation extension'), { 'fields': ('navigation_extension',), diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index db0f26748..d54b42b1f 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -7,15 +7,14 @@ from feincms.module.page.models import Page + def register(cls, admin_cls): cls.add_to_class('related_pages', models.ManyToManyField(Page, blank=True, related_name='%(app_label)s_%(class)s_related', null=True, help_text=_('Select pages that should be listed as related content.'))) - try: - admin_cls.filter_horizontal.append('related_pages') - except AttributeError: - admin_cls.filter_horizontal = ['related_pages'] + admin_cls.filter_horizontal = list(getattr(admin_cls, 'filter_horizontal', ())) + admin_cls.filter_horizontal.append('related_pages') admin_cls.add_extension_options(_('Related pages'), { 'fields': ('related_pages',), diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index befa7e1de..34f13cac6 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -1,7 +1,7 @@ -from django.utils.translation import ugettext_lazy as _ from django.conf import settings -from django.db import models from django.contrib.sites.models import Site +from django.db import models +from django.utils.translation import ugettext_lazy as _ from feincms.module.page.models import PageManager @@ -12,9 +12,8 @@ def current_site(queryset): def register(cls, admin_cls): cls.add_to_class('site', - models.ForeignKey(Site, - verbose_name=_('Site'), - default=settings.SITE_ID, )) + models.ForeignKey(Site, verbose_name=_('Site'), + default=settings.SITE_ID)) PageManager.add_to_active_filters(current_site, key='current_site') diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index ac19bb2c0..975288c06 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -9,6 +9,7 @@ from feincms._internal import monkeypatch_property + def register(cls, admin_cls): cls.add_to_class('_content_title', models.TextField(_('content title'), blank=True, help_text=_('The first line is the main title, the following lines are subtitles.'))) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 5b20bad7f..2a1952cb6 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -6,7 +6,6 @@ import re -from django import forms from django.contrib.admin.widgets import ForeignKeyRawIdWidget from django.contrib.sites.models import Site from django.db.models.loading import get_model @@ -16,7 +15,6 @@ from django.utils.translation import ugettext_lazy as _ from feincms import ensure_completely_loaded -from feincms.utils import shorten_string from mptt.forms import MPTTAdminForm @@ -129,14 +127,14 @@ def __init__(self, *args, **kwargs): pk = kwargs['instance'].pk if 'instance' in kwargs else None other_pages_for_template = pages_for_template.exclude(pk=pk) if template.singleton and other_pages_for_template.exists(): - continue # don't allow selection of singleton if in use + continue # don't allow selection of singleton if in use if template.preview_image: choices.append((template.key, mark_safe(u'%s %s' % ( - template.preview_image, - template.key, - template.title, - )))) + template.preview_image, + template.key, + template.title, + )))) else: choices.append((template.key, template.title)) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 0c6099445..9426d666f 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -21,6 +21,7 @@ # ------------------------------------------------------------------------ from .forms import PageAdminForm + # ------------------------------------------------------------------------ class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): class Media: @@ -41,7 +42,7 @@ class Media: ], }), (_('Other options'), { - 'classes': ['collapse',], + 'classes': ['collapse'], 'fields': unknown_fields, }), # <-- insertion point, extensions appear here, see insertion_index above @@ -51,7 +52,7 @@ class Media: list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] list_filter = ['active', 'in_navigation', 'template_key', 'parent'] search_fields = ['title', 'slug'] - prepopulated_fields = { 'slug': ('title',), } + prepopulated_fields = {'slug': ('title',)} raw_id_fields = ['parent'] radio_fields = {'template_key': admin.HORIZONTAL} @@ -103,7 +104,7 @@ def get_form(self, *args, **kwargs): return curry(form, modeladmin=self) def _actions_column(self, page): - addable = getattr(page, 'feincms_addable', True) + addable = getattr(page, 'feincms_addable', True) preview_url = "../../r/%s/%s/" % ( ContentType.objects.get_for_model(self.model).id, @@ -137,7 +138,7 @@ def _actions_column(self, page): return actions def add_view(self, request, **kwargs): - kwargs['form_url'] = request.get_full_path() # Preserve GET parameters + kwargs['form_url'] = request.get_full_path() # Preserve GET parameters if 'translation_of' in request.GET and 'language' in request.GET: try: original = self.model._tree_manager.get( @@ -210,7 +211,8 @@ def is_visible_admin(self, page): page is not visible because of publishing dates or inherited status. """ if not hasattr(self, "_visible_pages"): - self._visible_pages = list() # Sanity check in case this is not already defined + # Sanity check in case this is not already defined + self._visible_pages = list() if page.parent_id and not page.parent_id in self._visible_pages: # parent page's invisibility is inherited diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 8e48367a1..ce275cdef 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -92,7 +92,8 @@ def best_match_for_path(self, path, raise404=False): if path: tokens = path.split('/') - paths += ['/%s/' % '/'.join(tokens[:i]) for i in range(1, len(tokens)+1)] + paths += ['/%s/' % '/'.join(tokens[:i]) + for i in range(1, len(tokens) + 1)] try: page = self.active().filter(_cached_url__in=paths).extra( @@ -150,12 +151,13 @@ def for_request(self, request, raise404=False, best_match=False): return request._feincms_page + # ------------------------------------------------------------------------ class PageManager(BasePageManager): pass - PageManager.add_to_active_filters(Q(active=True)) + # ------------------------------------------------------------------------ @python_2_unicode_compatible class BasePage(create_base_model(MPTTModel), ContentModelMixin): @@ -166,7 +168,7 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): slug = models.SlugField(_('slug'), max_length=150, help_text=_('This is used to build the URL for this page')) parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, null=True, related_name='children') - parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py + parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py in_navigation = models.BooleanField(_('in navigation'), default=False) override_url = models.CharField(_('override URL'), max_length=255, blank=True, help_text=_('Override the target URL. Be sure to include slashes at the beginning and at the end if it is a local URL. This affects both the navigation and subpages\' URLs.')) @@ -176,9 +178,10 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): _cached_url = models.CharField(_('Cached URL'), max_length=255, blank=True, editable=False, default='', db_index=True) - cache_key_components = [ lambda p: getattr(django_settings, 'SITE_ID', 0), - lambda p: p._django_content_type.id, - lambda p: p.id ] + cache_key_components = [ + lambda p: getattr(django_settings, 'SITE_ID', 0), + lambda p: p._django_content_type.id, + lambda p: p.id] class Meta: ordering = ['tree_id', 'lft'] @@ -270,20 +273,17 @@ def save(self, *args, **kwargs): page.slug) cached_page_urls[page.id] = page._cached_url - super(BasePage, page).save() # do not recurse + super(BasePage, page).save() # do not recurse save.alters_data = True @commit_on_success def delete(self, *args, **kwargs): if not settings.FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED: if self.template.singleton: - raise PermissionDenied( - _(u'This %(page_class)s uses a singleton template, and ' - u'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False' % { - 'page_class': self._meta.verbose_name - } - ) - ) + raise PermissionDenied(_( + u'This %(page_class)s uses a singleton template, and ' + u'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False' % { + 'page_class': self._meta.verbose_name})) super(BasePage, self).delete(*args, **kwargs) self.invalidate_cache() delete.alters_data = True @@ -393,6 +393,7 @@ def register_default_processors(cls, frontend_editing=False): cls.register_response_processor(processors.frontendediting_response_processor, key='frontend_editing') + # ------------------------------------------------------------------------ class Page(BasePage): class Meta: diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 3c55faf32..70fe62cdd 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -158,7 +158,8 @@ def processor(page, request, response): for q in connection.queries: i += 1 if verbose: - print >> file, "%d : [%s]\n%s\n" % ( i, q['time'], print_sql(q['sql'])) + print >> file, "%d : [%s]\n%s\n" % ( + i, q['time'], print_sql(q['sql'])) time += float(q['time']) print >> file, "--------------------------------------------------------------" diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index 8a418c9f1..975e7b254 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -7,6 +7,7 @@ from feincms.module.page.models import Page + # ------------------------------------------------------------------------ class PageSitemap(Sitemap): """ @@ -33,15 +34,15 @@ def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset level, in_navigation and optionally modification_date. """ super(PageSitemap, self).__init__(*args, **kwargs) - self.depth_cutoff = max_depth - self.navigation_only = navigation_only - self.changefreq = changefreq - self.filter = filter + self.depth_cutoff = max_depth + self.navigation_only = navigation_only + self.changefreq = changefreq + self.filter = filter self.extended_navigation = extended_navigation if queryset is not None: - self.queryset = queryset + self.queryset = queryset else: - self.queryset = Page.objects.active() + self.queryset = Page.objects.active() def items(self): """ @@ -62,9 +63,9 @@ def items(self): if self.navigation_only: qs = qs.filter(in_navigation=True) if self.depth_cutoff > 0: - qs = qs.filter(level__lte=self.max_depth-1) + qs = qs.filter(level__lte=self.max_depth - 1) - pages = [ p for p in qs if p.is_active() ] + pages = [p for p in qs if p.is_active()] if self.extended_navigation: for idx, page in enumerate(pages): diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 4a74818a3..3b1f70365 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -5,27 +5,30 @@ import logging import sys import traceback -import warnings from django import template from django.conf import settings from django.http import HttpRequest from feincms.module.page.models import Page -from feincms.utils.templatetags import * -from feincms.utils.templatetags import _parse_args +from feincms.utils.templatetags import (SimpleNodeWithVarAndArgs, + do_simple_node_with_var_and_args_helper, + SimpleAssignmentNodeWithVarAndArgs, + do_simple_assignment_node_with_var_and_args_helper) + -# ------------------------------------------------------------------------ logger = logging.getLogger('feincms.templatetags.page') register = template.Library() + # ------------------------------------------------------------------------ # TODO: Belongs in some utility module def format_exception(e): top = traceback.extract_tb(sys.exc_info()[2])[-1] return u"'%s' in %s line %d" % (e, top[0], top[1]) + # ------------------------------------------------------------------------ @register.assignment_tag(takes_context=True) def feincms_nav(context, feincms_page, level=1, depth=1): @@ -156,6 +159,7 @@ def what(self, page, args): return '#' register.tag('feincms_parentlink', do_simple_node_with_var_and_args_helper(ParentLinkNode)) + # ------------------------------------------------------------------------ class LanguageLinksNode(SimpleAssignmentNodeWithVarAndArgs): """ @@ -206,14 +210,15 @@ def what(self, page, args): # hardcoded paths... bleh if key in translations: - links.append((key, name, translations[key].get_absolute_url()+trailing_path)) + links.append((key, name, + translations[key].get_absolute_url() + trailing_path)) elif not only_existing: links.append((key, name, None)) return links register.tag('feincms_languagelinks', do_simple_assignment_node_with_var_and_args_helper(LanguageLinksNode)) -# ------------------------------------------------------------------------ + # ------------------------------------------------------------------------ def _translate_page_into(page, language, default=None): """ @@ -235,6 +240,7 @@ def _translate_page_into(page, language, default=None): return default(page=page) return default + # ------------------------------------------------------------------------ class TranslatedPageNode(SimpleAssignmentNodeWithVarAndArgs): """ @@ -269,20 +275,23 @@ def what(self, page, args, default=None): return _translate_page_into(page, language, default=default) register.tag('feincms_translatedpage', do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNode)) + # ------------------------------------------------------------------------ class TranslatedPageNodeOrBase(TranslatedPageNode): def what(self, page, args): return super(TranslatedPageNodeOrBase, self).what(page, args, default=getattr(page, 'get_original_translation', page)) register.tag('feincms_translatedpage_or_base', do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNodeOrBase)) + # ------------------------------------------------------------------------ @register.filter def feincms_translated_or_base(pages, language=None): if not hasattr(pages, '__iter__'): - pages = [ pages ] + pages = [pages] for page in pages: yield _translate_page_into(page, language, default=page.get_original_translation) + # ------------------------------------------------------------------------ @register.inclusion_tag("breadcrumbs.html") def feincms_breadcrumbs(page, include_self=True): @@ -309,10 +318,12 @@ def feincms_breadcrumbs(page, include_self=True): return {"trail": bc} + # ------------------------------------------------------------------------ def _is_parent_of(page1, page2): return page1.tree_id == page2.tree_id and page1.lft < page2.lft and page1.rght > page2.rght + @register.filter def is_parent_of(page1, page2): """ @@ -328,10 +339,12 @@ def is_parent_of(page1, page2): except AttributeError: return False + # ------------------------------------------------------------------------ def _is_equal_or_parent_of(page1, page2): return page1.tree_id == page2.tree_id and page1.lft <= page2.lft and page1.rght >= page2.rght + @register.filter def is_equal_or_parent_of(page1, page2): """ @@ -349,10 +362,12 @@ def is_equal_or_parent_of(page1, page2): except AttributeError: return False + # ------------------------------------------------------------------------ def _is_sibling_of(page1, page2): return page1.parent_id == page2.parent_id + @register.filter def is_sibling_of(page1, page2): """ @@ -368,6 +383,7 @@ def is_sibling_of(page1, page2): except AttributeError: return False + # ------------------------------------------------------------------------ @register.filter def siblings_along_path_to(page_list, page2): @@ -397,7 +413,7 @@ def siblings_along_path_to(page_list, page2): # feincms_nav). We'll cope with the fall-out of that assumption # when it happens... ancestors = [a_page for a_page in page_list - if _is_equal_or_parent_of(a_page, page2)] + if _is_equal_or_parent_of(a_page, page2)] top_level = min((a_page.level for a_page in page_list)) if not ancestors: @@ -407,10 +423,12 @@ def siblings_along_path_to(page_list, page2): p = Page(title="dummy", tree_id=-1, parent_id=None, in_navigation=False) ancestors = (p,) - siblings = [a_page for a_page in page_list - if a_page.parent_id == page2.id or - a_page.level == top_level or - any((_is_sibling_of(a_page, a) for a in ancestors))] + siblings = [ + a_page for a_page in page_list + if a_page.parent_id == page2.id + or a_page.level == top_level + or any((_is_sibling_of(a_page, a) for a in ancestors))] + return siblings except (AttributeError, ValueError) as e: logger.warn("siblings_along_path_to caught exception: %s", format_exception(e)) diff --git a/feincms/signals.py b/feincms/signals.py index ce0e8d399..b921bc0e2 100644 --- a/feincms/signals.py +++ b/feincms/signals.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ # -# Created by Martin J. Laubach on 2011-08-01 +# Created by Martin J. Laubach on 2011-08-01 # Copyright (c) 2011 Martin J. Laubach. All rights reserved. # # ------------------------------------------------------------------------ diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index ca32950dc..cb0722250 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -7,6 +7,7 @@ # backwards compatibility import from feincms.templatetags.fragment_tags import fragment, get_fragment, has_fragment + register = template.Library() register.tag(fragment) @@ -31,7 +32,7 @@ def feincms_render_region_appcontent(page, region, request): from feincms.content.application.models import ApplicationContent from feincms.templatetags.feincms_tags import _render_content - return u''.join(_render_content(content, request=request) for content in\ + return u''.join(_render_content(content, request=request) for content in page.content.all_of_type(ApplicationContent) if content.region == region) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 122b3ba4e..227267e28 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -6,11 +6,11 @@ from django import template from django.conf import settings -from django.db.models import get_model from django.template.loader import render_to_string from feincms.utils import get_singleton, get_singleton_url + register = template.Library() @@ -28,8 +28,8 @@ def _render_content(content, **kwargs): return setattr(request, 'feincms_render_level', level + 1) - if (request and request.COOKIES.get('frontend_editing', False) and\ - hasattr(content, 'fe_render')): + if (request and request.COOKIES.get('frontend_editing', False) + and hasattr(content, 'fe_render')): r = content.fe_render(**kwargs) else: r = content.render(**kwargs) @@ -72,6 +72,7 @@ def feincms_frontend_editing(cms_obj, request): return u'' + @register.inclusion_tag('admin/feincms/content_type_selection_widget.html', takes_context=True) def show_content_type_selection_widget(context, region): """ diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 694c23039..7557e4e8a 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -103,7 +103,7 @@ def generate(self, storage, original, size, miniature): # defining the size w, h = int(size['w']), int(size['h']) - format = image.format # Save format for the save() call later + format = image.format # Save format for the save() call later image.thumbnail([w, h], Image.ANTIALIAS) buf = BytesIO() if image.mode not in ('RGBA', 'RGB', 'L'): @@ -163,8 +163,12 @@ def generate(self, storage, original, size, miniature): x_offset = 0 y_offset = int(float(src_height - crop_height) * y / 100) - format = image.format # Save format for the save() call later - image = image.crop((x_offset, y_offset, x_offset+int(crop_width), y_offset+int(crop_height))) + format = image.format # Save format for the save() call later + image = image.crop(( + x_offset, + y_offset, + x_offset + int(crop_width), + y_offset + int(crop_height))) image = image.resize((dst_width, dst_height), Image.ANTIALIAS) buf = BytesIO() diff --git a/feincms/templatetags/fragment_tags.py b/feincms/templatetags/fragment_tags.py index 2b01b6774..a3a46d156 100644 --- a/feincms/templatetags/fragment_tags.py +++ b/feincms/templatetags/fragment_tags.py @@ -1,5 +1,6 @@ from django import template + register = template.Library() @@ -24,7 +25,7 @@ def render(self, context): request._feincms_fragments[identifier] = rendered + old elif self.mode == 'replace': request._feincms_fragments[identifier] = rendered - else: # append + else: # append request._feincms_fragments[identifier] = old + rendered return u'' diff --git a/feincms/translations.py b/feincms/translations.py index ee12b92d8..a64e8714b 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -51,7 +51,6 @@ def short_language_code(code=None): """ Extract the short language code from its argument (or return the default language code). - >>> from django.conf import settings >>> short_language_code('de') 'de' >>> short_language_code('de-at') diff --git a/feincms/urls.py b/feincms/urls.py index 6344ad2ba..6b7582504 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -1,4 +1,4 @@ - +# flake8: noqa from __future__ import absolute_import from feincms.views.cbv.urls import * diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index ad56ac9ae..a8be246ed 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -18,6 +18,7 @@ from feincms import settings + # ------------------------------------------------------------------------ def get_object(path, fail_silently=False): # Return early if path isn't a string (might already be an callable or @@ -30,13 +31,14 @@ def get_object(path, fail_silently=False): except ImportError: try: dot = path.rindex('.') - mod, fn = path[:dot], path[dot+1:] + mod, fn = path[:dot], path[dot + 1:] return getattr(import_module(mod), fn) except (AttributeError, ImportError): if not fail_silently: raise + # ------------------------------------------------------------------------ def collect_dict_values(data): dic = {} @@ -44,6 +46,7 @@ def collect_dict_values(data): dic.setdefault(key, []).append(value) return dic + # ------------------------------------------------------------------------ def copy_model_instance(obj, exclude=None): """ @@ -52,13 +55,13 @@ def copy_model_instance(obj, exclude=None): """ exclude = exclude or () - initial = dict([(f.name, getattr(obj, f.name)) - for f in obj._meta.fields - if not isinstance(f, AutoField) and - not f.name in exclude and - not f in obj._meta.parents.values()]) + initial = dict( + (f.name, getattr(obj, f.name)) for f in obj._meta.fields + if not isinstance(f, AutoField) and not f.name in exclude + and not f in obj._meta.parents.values()) return obj.__class__(**initial) + # ------------------------------------------------------------------------ def shorten_string(str, max_length=50, ellipsis=u' … '): """ @@ -75,6 +78,7 @@ def shorten_string(str, max_length=50, ellipsis=u' … '): return str[:first_part] + ellipsis + str[-(max_length - first_part - len(ellipsis)):] return str + # ------------------------------------------------------------------------ def path_to_cache_key(path, max_length=200, prefix=""): """ @@ -100,8 +104,8 @@ def path_to_cache_key(path, max_length=200, prefix=""): ) return cache_key -# ------------------------------------------------------------------------ +# ------------------------------------------------------------------------ def get_singleton(template_key, cls=None, raise_exception=True): cls = cls or settings.FEINCMS_DEFAULT_PAGE_MODEL try: @@ -134,9 +138,9 @@ def get_singleton(template_key, cls=None, raise_exception=True): try: return model._default_manager.get(template_key=template_key) except model.DoesNotExist: - raise # not yet created? + raise # not yet created? except model.MultipleObjectsReturned: - raise # hmm, not exactly a singleton... + raise # hmm, not exactly a singleton... except Exception: if raise_exception: raise diff --git a/feincms/utils/html/tidy.py b/feincms/utils/html/tidy.py index 58ab84c9c..240dc1e78 100644 --- a/feincms/utils/html/tidy.py +++ b/feincms/utils/html/tidy.py @@ -47,17 +47,15 @@ def tidy_html(html): tidy_f = tidylib.tidy_fragment doc_mode = False - html, messages = tidy_f( - html.strip(), - { - "char-encoding": "utf8", - "clean": False, - "drop-empty-paras": False, - "drop-font-tags": True, - "drop-proprietary-attributes": False, - "fix-backslash": True, - "indent": True, - "output-xhtml": True, + html, messages = tidy_f(html.strip(), { + "char-encoding": "utf8", + "clean": False, + "drop-empty-paras": False, + "drop-font-tags": True, + "drop-proprietary-attributes": False, + "fix-backslash": True, + "indent": True, + "output-xhtml": True, } ) diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 2a66cbe6e..59f240c63 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -82,6 +82,7 @@ def lookup_tags(item_qs): from django.db import models + class TransformQuerySet(models.query.QuerySet): def __init__(self, *args, **kwargs): super(TransformQuerySet, self).__init__(*args, **kwargs) @@ -106,7 +107,7 @@ def iterator(self): return iter(results) return result_iter -class TransformManager(models.Manager): +class TransformManager(models.Manager): def get_query_set(self): return TransformQuerySet(self.model, using=self._db) diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index 24f266f56..f50c23319 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -11,6 +11,7 @@ from django import template + def _parse_args(argstr, context=None): try: args = {} @@ -32,6 +33,7 @@ def _parse_args(argstr, context=None): except TypeError: raise template.TemplateSyntaxError('Malformed arguments') + def do_simple_node_with_var_and_args_helper(cls): def _func(parser, token): try: @@ -49,6 +51,7 @@ def _func(parser, token): return _func + class SimpleNodeWithVarAndArgs(template.Node): def __init__(self, tag_name, in_var_name, args): self.tag_name = tag_name @@ -64,6 +67,7 @@ def render(self, context): return self.what(instance, _parse_args(self.args, context)) + def do_simple_assignment_node_with_var_and_args_helper(cls): def _func(parser, token): try: @@ -81,6 +85,7 @@ def _func(parser, token): return _func + class SimpleAssignmentNodeWithVarAndArgs(template.Node): def __init__(self, tag_name, in_var_name, var_name, args): self.tag_name = tag_name diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 85443a61c..17b20884c 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -4,8 +4,8 @@ from feincms import settings from feincms.module.mixins import ContentView -class Handler(ContentView): +class Handler(ContentView): page_model_path = 'page.Page' context_object_name = 'feincms_page' diff --git a/feincms/views/decorators.py b/feincms/views/decorators.py index a932c3b63..baaf8db08 100644 --- a/feincms/views/decorators.py +++ b/feincms/views/decorators.py @@ -1,8 +1,7 @@ +from functools import wraps + from django.http import HttpResponse -try: - from functools import wraps -except ImportError: - from django.utils.functional import wraps + def standalone(view_func): """ diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..6e39e3fe9 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +exclude= +ignore=E501,E123,E124,E126,E128 From 7869932dbaa8c88b87b213a315ce134f7631bd8f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 09:44:05 +0200 Subject: [PATCH 0756/1590] Fix #450, fix #452: No more crashes because of tuple/list problems with ModelAdmin extensions --- feincms/extensions.py | 14 ++++++++++++++ feincms/module/page/extensions/relatedpages.py | 7 +++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 9e484e072..e2047904c 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -126,6 +126,13 @@ def handle_modeladmin(self, modeladmin): pass +def _ensure_list(cls, attribute): + if cls is None: + return + value = getattr(cls, attribute, ()) or () + setattr(cls, attribute, list(value)) + + class LegacyExtension(Extension): """ Wrapper for legacy extensions @@ -150,18 +157,25 @@ def handle_model(self): def handle_modeladmin(self, modeladmin): if self.fieldsets: + _ensure_list(modeladmin, 'fieldsets') modeladmin.fieldsets.extend(self.fieldsets) if self.filter_horizontal: + _ensure_list(modeladmin, 'filter_horizontal') modeladmin.filter_horizontal.extend(self.filter_horizontal) if self.filter_vertical: + _ensure_list(modeladmin, 'filter_vertical') modeladmin.filter_vertical.extend(self.filter_vertical) if self.list_display: + _ensure_list(modeladmin, 'list_display') modeladmin.list_display.extend(self.list_display) if self.list_filter: + _ensure_list(modeladmin, 'list_filter') modeladmin.list_filter.extend(self.list_filter) if self.raw_id_fields: + _ensure_list(modeladmin, 'raw_id_fields') modeladmin.raw_id_fields.extend(self.raw_id_fields) if self.search_fields: + _ensure_list(modeladmin, 'search_fields') modeladmin.search_fields.extend(self.search_fields) if self.extension_options: diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index db0f26748..d54b42b1f 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -7,15 +7,14 @@ from feincms.module.page.models import Page + def register(cls, admin_cls): cls.add_to_class('related_pages', models.ManyToManyField(Page, blank=True, related_name='%(app_label)s_%(class)s_related', null=True, help_text=_('Select pages that should be listed as related content.'))) - try: - admin_cls.filter_horizontal.append('related_pages') - except AttributeError: - admin_cls.filter_horizontal = ['related_pages'] + admin_cls.filter_horizontal = list(getattr(admin_cls, 'filter_horizontal', ())) + admin_cls.filter_horizontal.append('related_pages') admin_cls.add_extension_options(_('Related pages'), { 'fields': ('related_pages',), From 8671e9979a4bd5890767d67d4f8a21a64df46d67 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:02:01 +0200 Subject: [PATCH 0757/1590] Add a ready-made, TinyMCE 4 compatible richtext template (from `next`) --- .../admin/content/richtext/init_tinymce4.html | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 feincms/templates/admin/content/richtext/init_tinymce4.html diff --git a/feincms/templates/admin/content/richtext/init_tinymce4.html b/feincms/templates/admin/content/richtext/init_tinymce4.html new file mode 100644 index 000000000..ca18de6c7 --- /dev/null +++ b/feincms/templates/admin/content/richtext/init_tinymce4.html @@ -0,0 +1,65 @@ +{% block tinymce_script %} + {% if TINYMCE_JS_URL %} + + {% endif %} +{% endblock %} + +{% block tinymce_init %} + +{% endblock %} From 16500190134d97cb0b08705011b92da576dfb57d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:02:10 +0200 Subject: [PATCH 0758/1590] FeinCMS v1.7.5 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 35c395d6d..8d6d44894 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 7, 4) +VERSION = (1, 7, 5) __version__ = '.'.join(map(str, VERSION)) From e15b0f74092494b89c05c2dc54c463a69a655cfa Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:09:56 +0200 Subject: [PATCH 0759/1590] Mention TinyMCE 3 and 4 --- docs/page.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/page.rst b/docs/page.rst index 614bb20e0..5bbdde7b2 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -305,19 +305,19 @@ exactly like ``register_request_processor`` above. It behaves in the same way. WYSIWYG Editors =============== -TinyMCE is configured by default to only allow for minimal formatting. This has proven +TinyMCE 3 is configured by default to only allow for minimal formatting. This has proven to be the best compromise between letting the client format text without destroying the -page design concept. You can customize the TinyMCE settings by creating your own +page design concept. You can customize the TinyMCE settings by creating your own init_richtext.html that inherits from `admin/content/richtext/init_tinymce.html`. You can even set your own CSS and linklist files like so:: - + FEINCMS_RICHTEXT_INIT_CONTEXT = { 'TINYMCE_JS_URL': STATIC_URL + 'your_custom_path/tiny_mce.js', 'TINYMCE_CONTENT_CSS_URL': None, # add your css path here 'TINYMCE_LINK_LIST_URL': None # add your linklist.js path here } -FeinCMS is set up to use TinyMCE_ but you can use CKEditor_ instead if you prefer +FeinCMS is set up to use TinyMCE_ 3 but you can use CKEditor_ instead if you prefer that one. Change the following settings:: FEINCMS_RICHTEXT_INIT_TEMPLATE = 'admin/content/richtext/init_ckeditor.html' @@ -325,6 +325,10 @@ that one. Change the following settings:: 'CKEDITOR_JS_URL': STATIC_URL + 'path_to_your/ckeditor.js', } +Alternatively, you can also use TinyMCE_ 4 by changing the following setting:: + + FEINCMS_RICHTEXT_INIT_TEMPLATE = 'admin/content/richtext/init_tinymce4.html' + .. _TinyMCE: http://www.tinymce.com/ .. _CKEditor: http://ckeditor.com/ From fa23958d8539fa72286c600feae6d3438f3be213 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:20:51 +0200 Subject: [PATCH 0760/1590] Fix #396: Make section content's use of template names consistent with the media library --- docs/releases/1.8.rst | 6 ++++++ feincms/content/section/models.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index f01f16027..17bb5f79d 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -12,6 +12,12 @@ Major feature 1 Backwards-incompatible changes ============================== +* The template naming and order used in the section content has been changed + to be more similar to the media library. The naming is now + ``_
``, additionally the media file type + is considered more important for template resolution than the section content + type. + Removal of deprecated features ------------------------------ diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 8ff2fd353..9b92ad54b 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -71,9 +71,9 @@ def render(self, **kwargs): mediafile_type = 'nomedia' return render_to_string([ - 'content/section/%s_%s.html' % (self.type, mediafile_type), - 'content/section/%s.html' % self.type, + 'content/section/%s_%s.html' % (mediafile_type, self.type), 'content/section/%s.html' % mediafile_type, + 'content/section/%s.html' % self.type, 'content/section/default.html', ], {'content': self}) From 85c9995cfecb925d14514380c14fd03ba7762799 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:24:52 +0200 Subject: [PATCH 0761/1590] Mention Python 3.3 in the v1.8 release notes --- docs/releases/1.8.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index 17bb5f79d..71975b7a9 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -5,8 +5,10 @@ FeinCMS 1.8 release notes (upcoming) Welcome to FeinCMS 1.8! -Major feature 1 -=============== +Python 3.3 support +================== + +The testsuite runs through on Python 3.3. Backwards-incompatible changes From 3eb4f54ada4dbd20aea4b62df617e57e80c2dedc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:29:00 +0200 Subject: [PATCH 0762/1590] .mailmap updates --- .mailmap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mailmap b/.mailmap index 642cb109d..4cd2bdad0 100644 --- a/.mailmap +++ b/.mailmap @@ -11,3 +11,5 @@ Nico Echaniz Bjorn Post Skylar Saveland Stephan Jaekel +Simon Bächler +Simon Bächler From 5d0363df85a295cad36412f6e565cc451eaa61a0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:36:30 +0200 Subject: [PATCH 0763/1590] Fix #408: Hack around NonExistentTimeError without a hard requirement on pytz --- feincms/module/extensions/datepublisher.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 4c35f60a4..f05c6f45d 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -63,7 +63,13 @@ def datepublisher_response_processor(page, request, response): if expires is not None: now = datetime.now() delta = expires - now - delta = int(delta.days * 86400 + delta.seconds) + + try: + delta = int(delta.days * 86400 + delta.seconds) + except Exception: + # This happens once every four years (or so) + delta = int(delta.days * 86400 + delta.seconds - 7200) + patch_response_headers(response, delta) From ff020164807c728fad68673435aa63688b45c29d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 11:57:35 +0200 Subject: [PATCH 0764/1590] python_2_unicode_compatible: Base.__str__ does not exist --- feincms/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index c6d82a163..04dc5e834 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -298,7 +298,6 @@ def create_base_model(inherit_from=models.Model): extend :class:`django.db.models.Model`. """ - @python_2_unicode_compatible class Base(inherit_from, ExtensionsMixin): """ This is the base class for your CMS models. It knows how to create and From de359bee8452db302b66e8b4dcdcc85b94f34d4e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 28 May 2013 08:54:20 +0200 Subject: [PATCH 0765/1590] Always process the Page.redirect_to field in the admin form --- feincms/module/page/forms.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index eb36d01ee..d89b497d8 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -152,6 +152,13 @@ def clean(self): if hasattr(Site, 'page_set') and 'site' in cleaned_data: active_pages = active_pages.filter(site=cleaned_data['site']) + # Convert PK in redirect_to field to something nicer for the future + redirect_to = cleaned_data.get('redirect_to') + if redirect_to and re.match(r'^\d+$', redirect_to): + opts = self.page_model._meta + cleaned_data['redirect_to'] = '%s.%s:%s' % ( + opts.app_label, opts.module_name, redirect_to) + if not cleaned_data['active']: # If the current item is inactive, we do not need to conduct # further validation. Note that we only check for the flag, not @@ -183,13 +190,6 @@ def clean(self): self._errors['active'] = ErrorList([_('This URL is already taken by another active page.')]) del cleaned_data['active'] - # Convert PK in redirect_to field to something nicer for the future - redirect_to = cleaned_data.get('redirect_to') - if redirect_to and re.match(r'^\d+$', redirect_to): - opts = self.page_model._meta - cleaned_data['redirect_to'] = '%s.%s:%s' % ( - opts.app_label, opts.module_name, redirect_to) - return cleaned_data # ------------------------------------------------------------------------ From 4c8cf02546e983f9d449f324a259da7e5f0d5f5e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Oct 2013 17:46:31 +0200 Subject: [PATCH 0766/1590] FeinCMS v1.7.6 This bug warrants another release. --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 8d6d44894..53891bf46 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 7, 5) +VERSION = (1, 7, 6) __version__ = '.'.join(map(str, VERSION)) From 3b9bd4e3f1932e30b2e56e3e4961890c06d8aac9 Mon Sep 17 00:00:00 2001 From: adsworth Date: Wed, 16 Oct 2013 22:26:50 +0200 Subject: [PATCH 0767/1590] use djangos default permission_denied view instead of the raw HTTPResponseForbidden In the section "Using page request processors" use djangos default permision_denied view instead of the HttpResponseForbidden. This will automatically pickup the 403.html template or return the string 403 Forbidden. --- docs/page.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/page.rst b/docs/page.rst index 614bb20e0..9758a9ed6 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -268,7 +268,7 @@ simple user access check can be implemented like this:: def authenticated_request_processor(page, request): if not request.user.is_authenticated(): - return HttpResponseForbidden() + return django.views.defaults.permission_denied() Page.register_request_processor(authenticated_request_processor) From 8619e2323011232967708021bab3d69dcb1b8e2e Mon Sep 17 00:00:00 2001 From: Jonas Svensson Date: Thu, 17 Oct 2013 16:05:15 +0200 Subject: [PATCH 0768/1590] Default manager name 'objects' is deprecated in favor of ModelAdmin.queryset. This allows use of custom managers and custom querysets. --- feincms/admin/tree_editor.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 855a8af96..27f3a74b5 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -39,7 +39,7 @@ def django_boolean_icon(field_val, alt_text=None, title=None): (django_settings.STATIC_URL, BOOLEAN_MAPPING[field_val], alt_text, title)) -def _build_tree_structure(cls): +def _build_tree_structure(queryset): """ Build an in-memory representation of the item tree, trying to keep database accesses down to a minimum. The returned dictionary looks like @@ -51,11 +51,16 @@ def _build_tree_structure(cls): ... } """ - all_nodes = { } - - mptt_opts = cls._mptt_meta - - for p_id, parent_id in cls.objects.order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr).values_list("pk", "%s_id" % mptt_opts.parent_attr): + all_nodes = {} + + mptt_opts = queryset.model._mptt_meta + items = queryset.order_by( + mptt_opts.tree_id_attr, + mptt_opts.left_attr) + values_list = items.values_list( + "pk", + "%s_id" % mptt_opts.parent_attr) + for p_id, parent_id in values_list: all_nodes[p_id] = [] if parent_id: @@ -352,8 +357,9 @@ def changelist_view(self, request, extra_context=None, *args, **kwargs): self._refresh_changelist_caches() extra_context = extra_context or {} + queryset = self.queryset(request) extra_context['tree_structure'] = mark_safe(json.dumps( - _build_tree_structure(self.model))) + _build_tree_structure(queryset))) return super(TreeEditor, self).changelist_view(request, extra_context, *args, **kwargs) @@ -389,8 +395,9 @@ def _move_node(self, request): else: tree_manager = self.model._tree_manager - cut_item = tree_manager.get(pk=request.POST.get('cut_item')) - pasted_on = tree_manager.get(pk=request.POST.get('pasted_on')) + queryset = self.queryset(request) + cut_item = queryset.get(pk=request.POST.get('cut_item')) + pasted_on = queryset.get(pk=request.POST.get('pasted_on')) position = request.POST.get('position') if position in ('last-child', 'left', 'right'): @@ -400,10 +407,6 @@ def _move_node(self, request): self.message_user(request, unicode(e)) return HttpResponse('FAIL') - # Ensure that model save has been run - cut_item = self.model.objects.get(pk=cut_item.pk) - cut_item.save() - self.message_user(request, ugettext('%s has been moved to a new position.') % cut_item) return HttpResponse('OK') From 8766533c64dc916620190c3009718a0abbb9f1f6 Mon Sep 17 00:00:00 2001 From: adsworth Date: Thu, 17 Oct 2013 16:15:04 +0200 Subject: [PATCH 0769/1590] use PermissionDenied exception in the page request processor example - In the page request processor example raise a PermisionDenied exception instead of calling the permission_denied view directly. - Updated the docs for the request processor to mention that if an exception is raised it will be handled like all exceptions are handled in django views. --- docs/page.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/page.rst b/docs/page.rst index 9758a9ed6..703670d7f 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -262,13 +262,15 @@ request as parameters and returns either None (or nothing) or a HttpResponse. All registered request processors are run before the page is actually rendered. If the request processor indeed returns a :class:`HttpResponse`, further rendering of the page is cut short and this response is returned immediately to the client. +It is also possible to raise an exception which will be handled like all exceptions +are handled in Django views. This allows for various actions dependent on page and request, for example a simple user access check can be implemented like this:: def authenticated_request_processor(page, request): if not request.user.is_authenticated(): - return django.views.defaults.permission_denied() + raise django.core.exceptions.PermissionDenied Page.register_request_processor(authenticated_request_processor) From 8f785603e61a0f08d58f4a0791aa3e9d5f1d7762 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 08:56:02 +0200 Subject: [PATCH 0770/1590] Add the code to update _cached_url values back --- feincms/admin/tree_editor.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 94da9f993..71081fa1d 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -454,6 +454,12 @@ def _move_node(self, request): self.message_user(request, u'%s' % e) return HttpResponse('FAIL') + # Ensure that model save method has been run (required to + # update Page._cached_url values, might also be helpful for other + # models inheriting MPTTModel) + cut_item = queryset.get(pk=cut_item.pk) + cut_item.save() + self.message_user(request, ugettext('%s has been moved to a new position.') % cut_item) return HttpResponse('OK') From 1f367b263d4730d9b4e042df99dd4ee1df2bac56 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 08:57:55 +0200 Subject: [PATCH 0771/1590] AUTHORS update --- AUTHORS | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0285331e9..a62c1c1d6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,6 +5,7 @@ The authors of FeinCMS are: * Chris Adams * Simon Meers * Bojan Mihelac +* Simon Bächler * Bjorn Post * Stephan Jaekel * Julien Phalip @@ -12,57 +13,77 @@ The authors of FeinCMS are: * Matt Dawson * Simon Schürpf * Skylar Saveland -* Simon Bächler * Stefan Reinhard +* Marc Egli +* Psyton +* Simon Schmid +* Greg Turner * Bjarni Thorisson * Greg Taylor * Maarten van Gompel (proycon) -* Psyton -* Simon Schmid * Antoni Aloy -* Marc Egli -* Urs Breton * Jonas +* Julian Bez +* Urs Breton +* Afonso Fernández Nogueira +* Marc Tamlyn * Martin Mahner * Max Peterson * Nico Echaniz +* Sander van Leeuwen * Toby White * Vítor Figueiró * Andrew D. Ball * Brian Macdonald * Eric Delord * Gabriel Kovacs +* Maarten Draijer * Torkn +* Cellarosi Marco +* Fabian Germann * Fabian Vogler * Håvard Grimelid * Maciek Szczesniak * Marco Fucci -* Maarten Draijer * Michael Bashkirov * Mikhail Korobov +* Raphael Jasjukaitis +* Richard A +* Vaclav Klecanda * Wil Tan +* adsworth * tayg * Alen Mujezinovic * Alex Kamedov * Andi Albrecht +* Andrey Popelo +* Andrin Heusser * Anshuman Bhaduri +* Charlie Denton +* Daniele Procida * Darryl Woods +* David Evans * Denis Martinez * Domas Lapinskas -* Fabian Germann * George Karpenkov * Harro van der Klauw * Jay Yu +* Jimmy Ye +* Jonas Svensson +* Laurent Paoletti * Livio Lunin -* Marc Tamlyn +* Marco Cellarosi * Mark Renton * Mason Hugus * Mikkel Hoegh * Olekasnadr Gula * Paul Garner +* Piet Delport +* Riccardo Coroneo +* Richard Bolt * Rico Moorman * Sebastian Hillig * Silvan Spross * Tobias Haffner -* Vaclav Klecanda +* Valtron * Wouter van der Graaf From 3aca52de4ec6fcd44e8ca5f72ea83f71fe6772e7 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 17 Oct 2013 13:54:42 +0200 Subject: [PATCH 0772/1590] Add option admin_list_display to contrib.tagging, so one can turn that off. Turning on the tags in admin's changelist incurs a db query for every item, which adds up fast. No idea why django-tagging is not using the value cached in the db field but instead rebuilds the tag list from scratch every time. --- feincms/contrib/tagging.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index d412ce6dd..3cccff42a 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -86,7 +86,7 @@ def pre_save_handler(sender, instance, **kwargs): # ------------------------------------------------------------------------ -def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_field=False, auto_add_admin_field=True): +def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_field=False, auto_add_admin_field=True, admin_list_display=True): """ tag_model accepts a number of named parameters: @@ -115,7 +115,8 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_fi return if admin_cls: - admin_cls.list_display.append(field_name) + if admin_list_display: + admin_cls.list_display.append(field_name) admin_cls.list_filter.append(field_name) if auto_add_admin_field and hasattr(admin_cls, 'add_extension_options'): From b88865a97fcffcb116cef7db1a991e6f6b2b1424 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 18 Oct 2013 10:46:57 +0200 Subject: [PATCH 0773/1590] tree_editor: Add the query set to the returned result set in the INCLUDE_ANCESTORS case. Django ORM is intelligent enough to optimise away the superfluous filter clauses in the common unfiltered case. --- feincms/admin/tree_editor.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 71081fa1d..d00189c83 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -166,8 +166,16 @@ def get_results(self, request): mptt_opts.right_attr, mptt_opts.tree_id_attr, )] + # We could optimise a bit here by explicitely filtering out + # any clauses that are for parents of nodes included in the + # queryset anyway. (ie: drop all clauses that refer to a node + # that is a parent to another node) + if clauses: - queryset = self.model._default_manager.filter( + # Note: Django ORM is smart enough to drop additional + # clauses if the initial query set is unfiltered. This + # is good. + queryset = self.query_set | self.model._default_manager.filter( reduce(lambda p, q: p | q, clauses)) if hasattr(self, 'queryset'): From 68254b2a82cc86d63b32f9b64d39d84428ee6984 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 18 Oct 2013 10:47:16 +0200 Subject: [PATCH 0774/1590] White space changes. --- feincms/admin/tree_editor.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index d00189c83..1ce8e3442 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -151,21 +151,21 @@ def __init__(self, request, *args, **kwargs): def get_query_set(self, *args, **kwargs): mptt_opts = self.model._mptt_meta - return super(ChangeList, self).get_query_set(*args, **kwargs).order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr) + return super(ChangeList, self).get_query_set(*args, **kwargs).\ + order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr) def get_results(self, request): mptt_opts = self.model._mptt_meta if settings.FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS: - clauses = [Q(**{ - mptt_opts.tree_id_attr: tree_id, - mptt_opts.left_attr + '__lte': lft, - mptt_opts.right_attr + '__gte': rght, - } - ) for lft, rght, tree_id in self.query_set.values_list( - mptt_opts.left_attr, - mptt_opts.right_attr, - mptt_opts.tree_id_attr, - )] + clauses = [Q(**{mptt_opts.tree_id_attr: tree_id, + mptt_opts.left_attr + '__lte': lft, + mptt_opts.right_attr + '__gte': rght, + }) + for lft, rght, tree_id in self.query_set.values_list( + mptt_opts.left_attr, + mptt_opts.right_attr, + mptt_opts.tree_id_attr, + )] # We could optimise a bit here by explicitely filtering out # any clauses that are for parents of nodes included in the # queryset anyway. (ie: drop all clauses that refer to a node From e1efe80309cfeb5babb3af2866dbcbb4a3595a48 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 14:32:59 +0200 Subject: [PATCH 0775/1590] Remove @commit_on_success, this should really not be necessary anymore --- feincms/module/page/models.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 5d90835be..c686b9442 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -13,7 +13,6 @@ from django.http import Http404 from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ -from django.db.transaction import commit_on_success from mptt.models import MPTTModel @@ -235,7 +234,6 @@ def __init__(self, *args, **kwargs): # determine whether it has been changed in the save handler: self._original_cached_url = self._cached_url - @commit_on_success def save(self, *args, **kwargs): """ Overridden save method which updates the ``_cached_url`` attribute of @@ -281,7 +279,6 @@ def save(self, *args, **kwargs): super(BasePage, page).save() # do not recurse save.alters_data = True - @commit_on_success def delete(self, *args, **kwargs): if not settings.FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED: if self.template.singleton: From 282ee43aceb72767761a34ac336adb73ef2b045a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 14:28:49 +0200 Subject: [PATCH 0776/1590] Ensure the PK field is rendered in inline admin forms --- feincms/templates/admin/feincms/content_inline.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templates/admin/feincms/content_inline.html b/feincms/templates/admin/feincms/content_inline.html index a0894755c..6187e9451 100644 --- a/feincms/templates/admin/feincms/content_inline.html +++ b/feincms/templates/admin/feincms/content_inline.html @@ -42,7 +42,7 @@

{{ inline_admin_formset.opts.verbose_name|title }}:  {% endfor %} - {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %} + {% if inline_admin_form.has_auto_field or inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} {{ inline_admin_form.fk_field.field }}

{% endfor %}

From ed01d31de5869d284ed63a36e32883dd11aa5c86 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 15:29:59 +0200 Subject: [PATCH 0777/1590] Use blog_entry_detail instead of blog_entry_details throughout --- example/blog_urls.py | 2 +- example/models.py | 2 +- example/templates/blog/entry_list.html | 2 +- tests/testapp/blog_urls.py | 2 +- tests/testapp/models.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/blog_urls.py b/example/blog_urls.py index 4a8c4138c..a199caaf4 100644 --- a/example/blog_urls.py +++ b/example/blog_urls.py @@ -7,7 +7,7 @@ urlpatterns = patterns('', url(r'^(?P\d+)/', generic.DetailView.as_view( queryset=Entry.objects.all(), - ), name='blog_entry_details'), + ), name='blog_entry_detail'), url(r'^$', generic.ListView.as_view( queryset=Entry.objects.all(), ), name='blog_entry_list'), diff --git a/example/models.py b/example/models.py index 3e50ff0ae..cfc697a66 100644 --- a/example/models.py +++ b/example/models.py @@ -69,7 +69,7 @@ def children(self, page, **kwargs): for entry in Entry.objects.all(): yield PagePretender( title=entry.title, - url=app_reverse('blog_entry_details', 'blog_urls', kwargs={'pk': entry.id}), + url=app_reverse('blog_entry_detail', 'blog_urls', kwargs={'pk': entry.id}), level=page.level + 1, ) diff --git a/example/templates/blog/entry_list.html b/example/templates/blog/entry_list.html index 3a47c7ff0..8a6d2b49a 100644 --- a/example/templates/blog/entry_list.html +++ b/example/templates/blog/entry_list.html @@ -1,5 +1,5 @@ {% load applicationcontent_tags %} {% for object in object_list %} -

{{ object.title }}

+

{{ object.title }}

{% endfor %} diff --git a/tests/testapp/blog_urls.py b/tests/testapp/blog_urls.py index 4a8c4138c..a199caaf4 100644 --- a/tests/testapp/blog_urls.py +++ b/tests/testapp/blog_urls.py @@ -7,7 +7,7 @@ urlpatterns = patterns('', url(r'^(?P\d+)/', generic.DetailView.as_view( queryset=Entry.objects.all(), - ), name='blog_entry_details'), + ), name='blog_entry_detail'), url(r'^$', generic.ListView.as_view( queryset=Entry.objects.all(), ), name='blog_entry_list'), diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 1fcc9af10..fe11e51f3 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -75,7 +75,7 @@ def children(self, page, **kwargs): for entry in Entry.objects.all(): yield PagePretender( title=entry.title, - url=reverse('testapp.blog_urls/blog_entry_details', kwargs={'object_id': entry.id}), + url=reverse('testapp.blog_urls/blog_entry_detail', kwargs={'object_id': entry.id}), ) Page.register_extensions( From dff12ef54201175cb31f10a0220b9c1d4ce19f4d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 15:30:24 +0200 Subject: [PATCH 0778/1590] Fix the URLconf location of blog_urls in the example --- example/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/example/models.py b/example/models.py index cfc697a66..51beb40e5 100644 --- a/example/models.py +++ b/example/models.py @@ -44,7 +44,10 @@ def get_admin_fields(form, *args, **kwargs): } Page.create_content_type(ApplicationContent, APPLICATIONS=( - ('blog_urls', 'Blog', {'admin_fields': get_admin_fields}), + ('blog_urls', 'Blog', { + 'admin_fields': get_admin_fields, + 'urls': 'example.blog_urls', + }), )) From 9fb1d56179e0e0903628c09e2a9522b7ef9db83b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 15:31:16 +0200 Subject: [PATCH 0779/1590] Make the new handler work everywhere, not only at the URLconf root Refs #321. --- feincms/module/page/models.py | 5 +++-- feincms/views/cbv/views.py | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c686b9442..89eaf9d7c 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -124,7 +124,8 @@ def toplevel_navigation(self): return self.in_navigation().filter(parent__isnull=True) - def for_request(self, request, raise404=False, best_match=False): + def for_request(self, request, raise404=False, best_match=False, + path=None): """ Return a page for the request @@ -139,7 +140,7 @@ def for_request(self, request, raise404=False, best_match=False): """ if not hasattr(request, '_feincms_page'): - path = request.path_info or request.path + path = path or request.path_info or request.path if best_match: request._feincms_page = self.best_match_for_path(path, diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 17b20884c..d5c9bfd45 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -18,8 +18,11 @@ def page_model(self): return self._page_model def get_object(self): + path = None + if self.args: + path = self.args[0] return self.page_model._default_manager.for_request( - self.request, raise404=True, best_match=True) + self.request, raise404=True, best_match=True, path=path) def dispatch(self, request, *args, **kwargs): try: From 699474839fbc27aa0a1fc67b2e886ac6b9ccc5d6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 17:11:56 +0200 Subject: [PATCH 0780/1590] Automatically install dependencies when using setup.py Refs #265. --- MANIFEST.in | 2 -- requirements.txt | 4 --- setup.py | 37 ++++++++++++++++++----- setuplib.py | 76 ------------------------------------------------ 4 files changed, 30 insertions(+), 89 deletions(-) delete mode 100644 requirements.txt delete mode 100644 setuplib.py diff --git a/MANIFEST.in b/MANIFEST.in index 167089faa..2b605a533 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,8 +2,6 @@ include AUTHORS include LICENSE include MANIFEST.in include README.rst -include requirements.txt -include setuplib.py recursive-include feincms/static * recursive-include feincms/locale * recursive-include feincms/templates * diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a26f05484..000000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -Django>=1.4.2 -django-mptt>=0.4 -Pillow -feedparser>=5.1.2 diff --git a/setup.py b/setup.py index 8038ffeb5..27b5fc423 100755 --- a/setup.py +++ b/setup.py @@ -1,22 +1,44 @@ #!/usr/bin/env python -from distutils.core import setup import os -import setuplib +from setuptools import setup, find_packages -packages, package_data = setuplib.find_packages('feincms') -setup(name='FeinCMS', +def read(filename): + return open(os.path.join(os.path.dirname(__file__), filename)).read() + + +setup( + name='FeinCMS', version=__import__('feincms').__version__, description='Django-based Page CMS and CMS building toolkit.', - long_description=open(os.path.join(os.path.dirname(__file__), 'README.rst')).read(), + long_description=read('README.rst'), author='Matthias Kestenholz', author_email='mk@feinheit.ch', url='http://github.com/feincms/feincms/', license='BSD License', platforms=['OS Independent'], - packages=packages, - package_data=package_data, + packages=find_packages( + exclude=['tests', 'example'], + ), + package_data={ + '': ['*.html', '*.txt'], + 'feincms': [ + 'locale/*/*/*', + 'static/feincms/*', + 'static/feincms/*/*', + 'templates/*', + 'templates/*/*', + 'templates/*/*/*', + 'templates/*/*/*/*', + ], + }, + install_requires=[ + 'Django>=1.4.2', + 'django-mptt>=0.6.0', + 'Pillow>=2.0.0', + 'feedparser>=5.0.0', + ], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', @@ -29,4 +51,5 @@ 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Application Frameworks', ], + zip_safe=False, ) diff --git a/setuplib.py b/setuplib.py deleted file mode 100644 index 52b32bb0a..000000000 --- a/setuplib.py +++ /dev/null @@ -1,76 +0,0 @@ -import os - -if not hasattr(os.path, 'relpath'): # python < 2.6 - # http://www.saltycrane.com/blog/2010/03/ospathrelpath-source-code-python-25/ - from posixpath import curdir, sep, pardir, join, abspath, commonprefix - - def relpath(path, start=curdir): - """Return a relative version of a path""" - if not path: - raise ValueError("no path specified") - start_list = abspath(start).split(sep) - path_list = abspath(path).split(sep) - # Work out how much of the filepath is shared by start and path. - i = len(commonprefix([start_list, path_list])) - rel_list = [pardir] * (len(start_list)-i) + path_list[i:] - if not rel_list: - return curdir - return join(*rel_list) - - os.path.relpath = relpath - -__all__ = ['find_files'] - - -def fullsplit(path, result=None): - """ - Split a pathname into components (the opposite of os.path.join) in a - platform-neutral way. - """ - if result is None: - result = [] - head, tail = os.path.split(path) - if head == '': - return [tail] + result - if head == path: - return result - return fullsplit(head, [tail] + result) - - -def find_packages(package_dir): - """ - Returns a tuple consisting of a ``packages`` list and a ``package_data`` - dictionary suitable for passing on to ``distutils.core.setup`` - - Requires the folder name containing the package files; ``find_files`` - assumes that ``setup.py`` is located in the same folder as the folder - containing those files. - - Code lifted from Django's ``setup.py``, with improvements by PSyton. - """ - - # Compile the list of packages available, because distutils doesn't have - # an easy way to do this. - packages = [] - package_data = {} - root_dir = os.path.dirname(__file__) - if root_dir != '': - os.chdir(root_dir) - - for dirpath, dirnames, filenames in sorted(os.walk(package_dir)): - # Ignore dirnames that start with '.' - for i, dirname in enumerate(dirnames): - if dirname.startswith('.'): del dirnames[i] - if '__init__.py' in filenames: - packages.append('.'.join(fullsplit(dirpath))) - elif filenames: - cur_pack = packages[0] # Assign all data files to the toplevel package - if cur_pack not in package_data: - package_data[cur_pack] = [] - package_dir = os.path.join(*cur_pack.split(".")) - dir_relpath = os.path.relpath(dirpath, package_dir) - for f in filenames: - package_data[cur_pack].append(os.path.join(dir_relpath, f)) - - return packages, package_data - From 14b83ba98013b0819432014480938127c4c64950 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 17:44:29 +0200 Subject: [PATCH 0781/1590] Files, not folders --- setup.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 27b5fc423..a6cf436f5 100755 --- a/setup.py +++ b/setup.py @@ -24,13 +24,13 @@ def read(filename): package_data={ '': ['*.html', '*.txt'], 'feincms': [ - 'locale/*/*/*', - 'static/feincms/*', - 'static/feincms/*/*', - 'templates/*', - 'templates/*/*', - 'templates/*/*/*', - 'templates/*/*/*/*', + 'locale/*/*/*.*', + 'static/feincms/*.*', + 'static/feincms/*/*.*', + 'templates/*.*', + 'templates/*/*.*', + 'templates/*/*/*.*', + 'templates/*/*/*/*.*', ], }, install_requires=[ From 569c455a5310b86a6f8c8bb4d6e9490f2fdbeee5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 10:42:49 +0200 Subject: [PATCH 0782/1590] Work on the release notes a bit --- docs/releases/1.8.rst | 55 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index 71975b7a9..6fde94c7f 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -5,12 +5,26 @@ FeinCMS 1.8 release notes (upcoming) Welcome to FeinCMS 1.8! -Python 3.3 support -================== +Preliminary Python 3.3 support +============================== The testsuite runs through on Python 3.3. +Singleton templates +=================== + +TODO document this. + + +Dependencies are automatically installed +======================================== + +Now that distribute and setuptools have merged, ``setup.py`` has been +converted to use setuptools again which means that all dependencies +of FeinCMS should be installed automatically. + + Backwards-incompatible changes ============================== @@ -24,6 +38,25 @@ Backwards-incompatible changes Removal of deprecated features ------------------------------ +* The module ``feincms.admin.editor`` has been removed. Import the classes + from ``feincms.admin.item_editor`` or ``feincms.admin.tree_editor`` directly. + +* The HTML cleansing module :mod:`feincms.utils.html.cleanse` has been removed. + Use the standalone package + `feincms-cleanse `_ instead. + +* Registering extensions using shorthand notation is not possible anymore. + Always use the full python path to the extension module. + +* The two navigation template tags ``feincms_navigation`` and + ``feincms_navigation_extended`` have been removed. The improved + ``feincms_nav`` tag has been introduced with FeinCMS v1.6. + +* The function-based generic views in :mod:`feincms.views.generic` have been + removed. The decorator function + :func:`feincms.views.decorators.add_page_to_extra_context` is therefore + obsolete and has also been removed. + * The old media library content type module :py:mod:`feincms.content.medialibrary.models` has been replaced with the contents of :py:mod:`feincms.content.medialibrary.v2`. The model field @@ -34,6 +67,9 @@ Removal of deprecated features removed in FeinCMS v1.8. The now-unused template ``admin/content/mediafile/init.html`` has been deleted. +* ``Page.setup_request()`` has been removed because it has not been doing + anything for some time now. + New deprecations ---------------- @@ -46,12 +82,25 @@ Notable features and improvements ================================= * The template tags ``feincms_render_region`` and ``feincms_render_content`` - do not require a request object anymore. + do not require a request object anymore. If you omit the ``request`` + parameter, the request will not be passed to the ``render()`` methods. + +* The code is mostly `flake8 `_ clean. + +* The new management command ``medialibrary_orphans`` can be used to find + files which aren't referenced in the media library anymore. + +* The test suite has been moved into its own top-level module. Bugfixes ======== +* The item and tree editor finally take Django permissions into account. + +* The datepublisher response processor should not crash during daylight + savings time changes anymore. + Compatibility with Django and other apps ======================================== From d5979b2e9d7ccc8b74815f5e9f91720a1b7c850e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 11:25:53 +0200 Subject: [PATCH 0783/1590] Fix a typo in the documentation --- docs/deprecation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index bb793ccd8..63fa9f61f 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -69,7 +69,7 @@ will be issued for at least two releases. Page.register_extensions( 'feincms.module.page.extensions.navigation', - 'feincmc.module.extensions.ct_tracker', + 'feincms.module.extensions.ct_tracker', ) * ``feincms_navigation`` and ``feincms_navigation_extended`` will be removed. From 544418790a383bb105dd55f11067e19df245a944 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 11:26:16 +0200 Subject: [PATCH 0784/1590] _build_tree_structure: do not reference removed variables --- feincms/admin/tree_editor.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 1ce8e3442..765b469f8 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -75,7 +75,11 @@ def _build_tree_structure(queryset): # we have yet to iteratove over. Happens with broken MPTT # hierarchy. all_nodes[parent_id] = [] - logger.warn("Incorrect MPTT hierarchy for %s, node %d has left_attr < than one of its parents. Try rebuilding mptt data (use '%s._default_manager.rebuild()').", cls.__name__, p_id, cls.__name__) + logger.warn( + "Incorrect MPTT hierarchy for %s, node %d has left_attr" + " < than one of its parents. Try rebuilding mptt data (use" + " '%s._default_manager.rebuild()').", + queryset.model.__name__, p_id, queryset.model.__name__) all_nodes[parent_id].append(p_id) From 397b76bdb8f419582a73567c246f9f52b16a8ec2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 11:26:26 +0200 Subject: [PATCH 0785/1590] Fix a tiny flake8 complaint --- feincms/module/page/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 89eaf9d7c..42ddf1064 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -170,7 +170,7 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): help_text=_('This is used to build the URL for this page')) parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, null=True, related_name='children') - parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py + parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py in_navigation = models.BooleanField(_('in navigation'), default=False) override_url = models.CharField(_('override URL'), max_length=255, blank=True, help_text=_('Override the target URL. Be sure to include slashes at the ' From a491ffd9df80705c251e82c2aac3029317b53516 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 11:44:12 +0200 Subject: [PATCH 0786/1590] Gettext string fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks Simon Bächler for the report. --- feincms/module/page/modeladmins.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 9426d666f..f02819ae8 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -151,12 +151,10 @@ def add_view(self, request, **kwargs): django_settings.LANGUAGES).get(language_code, '') kwargs['extra_context'] = { 'adding_translation': True, - 'title': _( - u'Add %(language)s Translation of "%(page)s"' % { - 'language': language, - 'page': original, - } - ), + 'title': _('Add %(language)s translation of "%(page)s"') % { + 'language': language, + 'page': original, + }, 'language_name': language, 'translation_of': original, } From 6b6c3b49645d35dcd97c0bd9cecca1204ce901ec Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 14:49:02 +0200 Subject: [PATCH 0787/1590] This is not necessary anymore, we do not support Django versions <1.4 anymore --- feincms/module/page/sitemap.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index 975e7b254..89d22c760 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -109,14 +109,4 @@ def priority(self, obj): return "%0.2g" % min(1.0, prio) - # After a call to the sitemap, be sure to erase the cached _paginator - # attribute, so next time we'll re-fetch the items list instead of using - # a stale list. - # This has been fixed in Django r17468 - def get_urls(self, *args, **kwargs): - urls = super(PageSitemap, self).get_urls(*args, **kwargs) - if hasattr(self, '_paginator'): - del(self._paginator) - return urls - # ------------------------------------------------------------------------ From 8872e3c1456b4f3a735cdb7cd7023f285b06b5b2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 14:51:03 +0200 Subject: [PATCH 0788/1590] Also clobber the app_reverse cache when saving pages --- feincms/content/application/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 48b856a43..8a0d082e2 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -303,11 +303,13 @@ def save(self, commit=True, *args, **kwargs): cls.feincms_item_editor_form = ApplicationContentItemEditorForm # Make sure the patched reverse() method has all information it needs - cls.parent.field.rel.to.register_request_processor( - retrieve_page_information) + page_class = cls.parent.field.rel.to + page_class.register_request_processor(retrieve_page_information) signals.post_save.connect(_empty_reverse_cache, sender=cls) signals.post_delete.connect(_empty_reverse_cache, sender=cls) + signals.post_save.connect(_empty_reverse_cache, sender=page_class) + signals.post_delete.connect(_empty_reverse_cache, sender=page_class) def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) From 5505c97b277ba20a46fb6c050130b1612d71f766 Mon Sep 17 00:00:00 2001 From: adsworth Date: Mon, 21 Oct 2013 21:00:52 +0200 Subject: [PATCH 0789/1590] In the docs, mention that FEINCMS_RICHTEXT_INIT_TEMPLATE needs to be set if using TinyMCE 4.x When using TinyMCE 4.x the user has to set FEINCMS_RICHTEXT_INIT_TEMPLATE to the init_tinymce4.html template for the rich text content to work correctly. --- feincms/content/richtext/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index f15c580ce..13a9c2c22 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -64,6 +64,9 @@ class RichTextContent(models.Model): anything you want using ``FEINCMS_RICHTEXT_INIT_CONTEXT`` and ``FEINCMS_RICHTEXT_INIT_TEMPLATE``. + If you are using TinyMCE 4.x then ``FEINCMS_RICHTEXT_INIT_TEMPLATE`` + needs to be set to ``admin/content/richtext/init_tinymce4.html``. + Optionally runs the HTML code through HTML cleaners if you specify ``cleanse=True`` when calling ``create_content_type``. """ From 97fbfe1ca51ee5468b9b4479fdd69c6db4378ef3 Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Tue, 22 Oct 2013 17:50:39 +0100 Subject: [PATCH 0790/1590] Use python 3 compatible print statements. --- example/test_utils.py | 12 +++++++----- feincms/management/commands/feincms_validate.py | 7 ++++--- .../management/commands/medialibrary_orphans.py | 4 +++- feincms/management/commands/rebuild_mptt.py | 3 ++- feincms/module/page/processors.py | 14 ++++++++------ 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/example/test_utils.py b/example/test_utils.py index 412540d0b..701f61c2e 100644 --- a/example/test_utils.py +++ b/example/test_utils.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import print_function + from django.conf import settings from django.test.simple import DjangoTestSuiteRunner @@ -17,15 +19,15 @@ def run_tests(self, *args, **kwargs): if run_with_coverage: coverage.stop() - print '' - print '----------------------------------------------------------------------' - print ' Unit Test Code Coverage Results' - print '----------------------------------------------------------------------' + print('') + print('----------------------------------------------------------------------') + print(' Unit Test Code Coverage Results') + print('----------------------------------------------------------------------') coverage_modules = [] for module in settings.COVERAGE_MODULES: coverage_modules.append(__import__(module, globals(), locals(), [''])) coverage.report(coverage_modules, show_missing=1) - print '----------------------------------------------------------------------' + print('----------------------------------------------------------------------') return result diff --git a/feincms/management/commands/feincms_validate.py b/feincms/management/commands/feincms_validate.py index d76d26ff7..7b7ee0b9b 100644 --- a/feincms/management/commands/feincms_validate.py +++ b/feincms/management/commands/feincms_validate.py @@ -7,6 +7,7 @@ ``feincms_validate`` checks your models for common pitfalls. """ +from __future__ import print_function from django.core.management.base import NoArgsCommand from django.core.management.color import color_style @@ -21,7 +22,7 @@ class Command(NoArgsCommand): def handle_noargs(self, **options): self.style = color_style() - print "Running Django's own validation:" + print("Running Django's own validation:") self.validate(display_num_errors=True) for model in loading.get_models(): @@ -38,7 +39,7 @@ def validate_base_model(self, model): """ if not hasattr(model, 'template'): - print self.style.NOTICE('%s has no template attribute; did you forget register_templates or register_regions?' % model) + print(self.style.NOTICE('%s has no template attribute; did you forget register_templates or register_regions?' % model)) def validate_content_type(self, model): """ @@ -47,4 +48,4 @@ def validate_content_type(self, model): for base in model.__bases__: if not base._meta.abstract: - print self.style.NOTICE('One of %s bases, %s, is not abstract' % (model, base)) + print(self.style.NOTICE('One of %s bases, %s, is not abstract' % (model, base))) diff --git a/feincms/management/commands/medialibrary_orphans.py b/feincms/management/commands/medialibrary_orphans.py index 4f1b50d70..19997218a 100644 --- a/feincms/management/commands/medialibrary_orphans.py +++ b/feincms/management/commands/medialibrary_orphans.py @@ -1,3 +1,5 @@ +from __future__ import print_function + import os from django.core.management.base import NoArgsCommand @@ -17,4 +19,4 @@ def handle_noargs(self, **options): for f in files: full = os.path.join(base[6:], f) if force_text(full) not in mediafiles: - print os.path.join(base, f) + print(os.path.join(base, f)) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index 5442e9f43..f16f57a40 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -7,6 +7,7 @@ ``rebuild_mptt`` rebuilds your mptt pointers. Only use in emergencies. """ +from __future__ import print_function from django.core.management.base import NoArgsCommand @@ -17,5 +18,5 @@ class Command(NoArgsCommand): help = "Run this manually to rebuild your mptt pointers. Only use in emergencies." def handle_noargs(self, **options): - print "Rebuilding MPTT pointers for Page" + print("Rebuilding MPTT pointers for Page") Page._tree_manager.rebuild() diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 70fe62cdd..69f626509 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -1,3 +1,5 @@ +from __future__ import print_function + import re import sys @@ -152,18 +154,18 @@ def processor(page, request, response): pass if verbose: - print >> file, "--------------------------------------------------------------" + print("--------------------------------------------------------------", file=file) time = 0.0 i = 0 for q in connection.queries: i += 1 if verbose: - print >> file, "%d : [%s]\n%s\n" % ( - i, q['time'], print_sql(q['sql'])) + print("%d : [%s]\n%s\n" % ( + i, q['time'], print_sql(q['sql'])), file=file) time += float(q['time']) - print >> file, "--------------------------------------------------------------" - print >> file, "Total: %d queries, %.3f ms" % (i, time) - print >> file, "--------------------------------------------------------------" + print("--------------------------------------------------------------", file=file) + print("Total: %d queries, %.3f ms" % (i, time), file=file) + print("--------------------------------------------------------------", file=file) return processor From 0be03dc39f17b99bb4546ca8df55743a4f32d54b Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Wed, 23 Oct 2013 11:04:05 +0100 Subject: [PATCH 0791/1590] Python 3 unicode compatibility. --- feincms/admin/filterspecs.py | 9 +++++---- feincms/contrib/tagging.py | 3 ++- feincms/module/medialibrary/fields.py | 3 ++- feincms/templatetags/feincms_thumbnail.py | 3 ++- feincms/utils/compat.py | 13 +++++++++++++ feincms/utils/html/tidy.py | 4 +++- 6 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 feincms/utils/compat.py diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index e1d698454..1b20b1641 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -5,11 +5,12 @@ # Guilherme M. Gondim (semente) from django.contrib.admin.filters import FieldListFilter, ChoicesFieldListFilter -from django.utils.encoding import smart_unicode +from django.utils.encoding import smart_text from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ from feincms.utils import shorten_string +from feincms.utils.compat import text_type class ParentFieldListFilter(ChoicesFieldListFilter): @@ -39,7 +40,7 @@ def choices(self, cl): yield { 'selected': pk == int(self.lookup_val or '0'), 'query_string': cl.get_query_string({self.lookup_kwarg: pk}), - 'display': mark_safe(smart_unicode(title)) + 'display': mark_safe(smart_text(title)) } def title(self): @@ -58,7 +59,7 @@ def __init__(self, f, request, params, model, model_admin, field_path=None): # Restrict results to categories which are actually in use: self.lookup_choices = [ - (i.pk, unicode(i)) for i in f.related.parent_model.objects.exclude(**{ + (i.pk, text_type(i)) for i in f.related.parent_model.objects.exclude(**{ f.related.var_name: None }) ] @@ -75,7 +76,7 @@ def choices(self, cl): yield { 'selected': pk == int(self.lookup_val or '0'), 'query_string': cl.get_query_string({self.lookup_kwarg: pk}), - 'display': mark_safe(smart_unicode(title)) + 'display': mark_safe(smart_text(title)) } def title(self): diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 3cccff42a..f029a6b48 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -18,6 +18,7 @@ from tagging.fields import TagField from tagging import AlreadyRegistered +from feincms.utils.compat import text_type # ------------------------------------------------------------------------ def taglist_to_string(taglist): @@ -68,7 +69,7 @@ def _render(name, value, attrs=None, *args, **kwargs): return type(widget).render(widget, name, value, attrs, *args, **kwargs) widget.render = _render defaults['widget'] = widget - choices = [(str(t), str(t)) for t in Tag.objects.all()] + choices = [(text_type(t), text_type(t)) for t in Tag.objects.all()] return TagSelectFormField(choices=choices, required=not self.blank, **defaults) diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index ae614ea38..71654ba07 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -13,6 +13,7 @@ from feincms.admin.item_editor import FeinCMSInline from feincms.utils import shorten_string +from feincms.utils.compat import text_type from .models import MediaFile from .thumbnail import admin_thumbnail @@ -30,7 +31,7 @@ def label_for_value(self, value): try: obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) label = [u' %s' % escape( - shorten_string(unicode(obj)))] + shorten_string(text_type(obj)))] image = admin_thumbnail(obj) if image: diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 7557e4e8a..6cfe00506 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -23,6 +23,7 @@ from django.core.files.base import ContentFile from feincms import settings +from feincms.utils.compat import text_type register = template.Library() @@ -39,7 +40,7 @@ def __init__(self, filename, size='200x200'): @property def url(self): - return unicode(self) + return text_type(self) def __str__(self): match = self.THUMBNAIL_SIZE_RE.match(self.size) diff --git a/feincms/utils/compat.py b/feincms/utils/compat.py new file mode 100644 index 000000000..126775e3a --- /dev/null +++ b/feincms/utils/compat.py @@ -0,0 +1,13 @@ +"""Compatibility shims.""" +import sys + + +# Python 2/3 compatiibility. +# From http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ +PY2 = sys.version_info[0] == 2 +if not PY2: + text_type = str + unichr = chr +else: + text_type = unicode + unichr = unichr diff --git a/feincms/utils/html/tidy.py b/feincms/utils/html/tidy.py index 240dc1e78..320548582 100644 --- a/feincms/utils/html/tidy.py +++ b/feincms/utils/html/tidy.py @@ -3,6 +3,8 @@ import re import tidylib +from feincms.utils.compat import text_type, unichr + # Based on http://stackoverflow.com/questions/92438/stripping-non-printable-characters-from-a-string-in-python # # We omit chars 9-13 (tab, newline, vertical tab, form feed, return) and 32 @@ -24,7 +26,7 @@ def tidy_html(html): Input must be unicode. Output will be valid XHTML. """ - if not isinstance(html, unicode): + if not isinstance(html, text_type): raise ValueError("tidyhtml must be called with a Unicode string!") errors = list() From a56b36f4359bca64240d0ca85acd9b45f8a8d9ce Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 25 Oct 2013 11:16:40 +0200 Subject: [PATCH 0792/1590] Push/pull translations from transifex --- .tx/config | 8 + feincms/locale/ca/LC_MESSAGES/django.mo | Bin 12240 -> 12041 bytes feincms/locale/ca/LC_MESSAGES/django.po | 314 ++++----- feincms/locale/cs/LC_MESSAGES/django.mo | Bin 13105 -> 12819 bytes feincms/locale/cs/LC_MESSAGES/django.po | 247 ++++---- feincms/locale/de/LC_MESSAGES/django.mo | Bin 15148 -> 15382 bytes feincms/locale/de/LC_MESSAGES/django.po | 309 ++++----- feincms/locale/en/LC_MESSAGES/django.mo | Bin 378 -> 378 bytes feincms/locale/en/LC_MESSAGES/django.po | 231 ++++--- feincms/locale/es/LC_MESSAGES/django.mo | Bin 16126 -> 12216 bytes feincms/locale/es/LC_MESSAGES/django.po | 401 ++++++------ feincms/locale/fr/LC_MESSAGES/django.mo | Bin 9413 -> 9139 bytes feincms/locale/fr/LC_MESSAGES/django.po | 325 +++++----- feincms/locale/hr/LC_MESSAGES/django.mo | Bin 12350 -> 12148 bytes feincms/locale/hr/LC_MESSAGES/django.po | 320 ++++------ feincms/locale/it/LC_MESSAGES/django.mo | Bin 13731 -> 8514 bytes feincms/locale/it/LC_MESSAGES/django.po | 556 ++++++++-------- feincms/locale/nb/LC_MESSAGES/django.mo | Bin 11965 -> 11786 bytes feincms/locale/nb/LC_MESSAGES/django.po | 311 ++++----- feincms/locale/nl/LC_MESSAGES/django.mo | Bin 12229 -> 15507 bytes feincms/locale/nl/LC_MESSAGES/django.po | 394 ++++++------ feincms/locale/pl/LC_MESSAGES/django.mo | Bin 9999 -> 9946 bytes feincms/locale/pl/LC_MESSAGES/django.po | 301 ++++----- feincms/locale/pt/LC_MESSAGES/django.mo | Bin 15422 -> 15186 bytes feincms/locale/pt/LC_MESSAGES/django.po | 343 +++++----- feincms/locale/pt_BR/LC_MESSAGES/django.mo | Bin 14296 -> 14112 bytes feincms/locale/pt_BR/LC_MESSAGES/django.po | 339 +++++----- feincms/locale/ro/LC_MESSAGES/django.mo | Bin 9206 -> 8931 bytes feincms/locale/ro/LC_MESSAGES/django.po | 309 ++++----- feincms/locale/ru/LC_MESSAGES/django.mo | Bin 8692 -> 8568 bytes feincms/locale/ru/LC_MESSAGES/django.po | 291 ++++----- feincms/locale/tr/LC_MESSAGES/django.mo | Bin 464 -> 15383 bytes feincms/locale/tr/LC_MESSAGES/django.po | 698 ++++++++++----------- feincms/locale/zh_CN/LC_MESSAGES/django.mo | Bin 12900 -> 12710 bytes feincms/locale/zh_CN/LC_MESSAGES/django.po | 303 ++++----- 35 files changed, 2724 insertions(+), 3276 deletions(-) create mode 100644 .tx/config diff --git a/.tx/config b/.tx/config new file mode 100644 index 000000000..492a3add3 --- /dev/null +++ b/.tx/config @@ -0,0 +1,8 @@ +[main] +host = https://www.transifex.com +type = PO + +[feincms.djangopo] +file_filter = feincms/locale//LC_MESSAGES/django.po +source_file = feincms/locale/en/LC_MESSAGES/django.po +source_lang = en diff --git a/feincms/locale/ca/LC_MESSAGES/django.mo b/feincms/locale/ca/LC_MESSAGES/django.mo index ceeed6b2f61f613b2e4718d28c5f03fadde18ebb..f16f42f8e9c0a843501d757bb4bea5dfcd3d4604 100644 GIT binary patch delta 4267 zcmZA43vg7`0mkvOJVO#7yh0!ZmiHss?1KcuQk6$YP(m>XN&t~f2+2xbW;cn3(#2vh z5lhuA0yZGg3Sv>A+em8Fw${Sv)DFcCBOPeVOtrPsVrLk~+E(fR+k4_nduP7<&bfQ; zdEEzk{@$+5vEPp#wBK;_kxAt8U}OG`-D&*c=p1Rx7VN@t_*cwElVQvZn1l;)368)W zn2wJkU6}(o5D%jtd+ho5afmT7bIB=~KjL^A{25d629CzmQN|Qw4yIrw4#VxpTuciN z#}3TIIBvriQP+>+k0w3?XJHUE!4PIJzGp|FHu`KhKlOb_%i`-Le01wwbIRa z1ncbiG?rIHJqtDAa#Z{EsD)Ld7F3T~Kr0sDE{rjz>7}3x-a!p;5!LWds1;sAt>8K? zz!B{8MqG~iy$99)n5~~e_1BA<&|CKWJE#f$8g)xAX0rbs6tcPTdDw$~HNbo{S;ka> z7Xui_`FIx9@xM@8?P8lW;7}~Zv8aJIq1tUl-HPp~1-BuaXZB8D|Cx+A$_ZU?2KDg$ z6t!jVTHi+va2d5jAEVlTX6rYs!`UY7L^kU8nW*+2)J`ozO=PjHm&I(M9Fq?XCTDKl zYR}i%dNXQ*?WhTMpgP`%8aQq}Y(0+Z_q6p4YDeBcO)T~{1zmW-dKuO6N2nElf*RmI zsDWL){4yQ2bK_C3Z9ZycCCHm=)}RKcLf%AkKdPVIsIBirz6&vPn1VX&K@EHoHE=KL zg17AN=TIxTfLg%^w*CjybswTSzGiOY8SdjCu9i93@g_}ZZc zs6$;4K}~Qc>eh6k27DYf!9(`^5!CB@3^mbSR6jq#s>c>1xNdSHsv@5315oH;~c zCZ54t@Cx!~nMrQv(^-g``AXElYcUTiPy_F=K870jN#x^b4xyfblc;fC!xi`eYJpRy zvj199?o?++MW`)Yg?wwwCVUW^QCs#mdraA2kQ9D(PnrH>8eI=^@2L`qCj%me(_!Ji5dDK5f!)7=WnSfeI zKI-kb8Qr)JbxT_9@0~FUhdFToH9#Tvp#+!WAnZbIsAi8;9X>TR)9@wq8g5`(rNH1|OpyqU)$FPsw%eX*Ld~ zo{QQEzpXFDH0mpCeJyGM8>}IFz7{p12Gl~^Y(0jljBh$AXvJ~VKu1xZ)?=u9{s!tb z`W0$`-&wDsI{XXj;roZJ>)lMHo`PyW2G!q0Tlb^-E5eutD4{SJ*P$Dus1Em|R{T8b zf>%*H^fnH}OQoU?c-ML!b>T(S zg;!8B{lwNkLl^ZI$!W5HJV%}++?@ z@)Bt$kC8gEn&|jC`A)Lr{6D~bwtNP)2;S%9S5e=A?c^S^o_v?wPx^>X@<6imzkl?GJZn$2q2Bd!(rC}=dC*ZyzL6|BU({Y();8-nNW96C^XFSh)Vn?E zaV_~aiIY9#F0zCKh>j{Uf;1D|9vymfbc+gA;V5=U{!hqB%06;83EK0bf)uEr@$*#R z&@1&k@vCBw+pJ5mm3)uPC$q>FvYbSSj#o(~8K(-z!{lb7H|H60gz(^-y`-Axi0Ns~ zBAsLvxry{2dQ}dPmr2N;9B!S8_mZ8q-em3PhZMHj%4X|4`~lfu>ku=$_`8WbK^`G1 z$>U@V`Tyhl_QY;$iuF!hX3H74*p}yF*p_Q>rY#@0-jUpYDmkQwxXCM|fpn2>@*}d3 z=s!5}NhXPsbaFc>BkRZsGMeaknk2|{(m}?O8KnQv$L&#at4=;h1`xgXI=)68A}^3* z#KgZC`Fi4PM&ICgN9J!5?c@JGAW=WD#FgmF-s?)-mNU*Zr#2dG3VOXY;b?73Wqws- zy?0x6xS^^(@|EF8q@_9%-#mGI!F-S3=LrDG>SnqBh62CO-)5MM0r2`Wy SbDwb~uIHU|C4QEl;rcJ6t*~7H delta 4450 zcmYk;4OG?T0mt#@@*+xC1T<58yO07ZAdo1MnGO^UGEHbKQ@X|iCkLNDDswXGqvMZwsy939k(54t>ex%*U_chI;Goj-`~BD<^TA*pXd3%Ja7LO zT)*(++Tf?Dahna>5i*oGdl}`;v{?@lhC9@ z_xHniszWgrGq3g;o#VLcIwSaSf*8GgyW@u{Zt=`{0+@53gWfOyuN& zI0zeX9P0Y#_|XLRU?v_#rwJPKR|*W;{0kE>uD>ywyc5;YAk+ZUQ8UR#b)1I*EXFwO zw(iASsqaUfe+Jdw=a_~Ua6I-NU`!GHn>#3I27ct9Sk3iz$*6Xxp{}2eTA}J&Sbv?cj2#-`N-V=Cu^m6c9Gp8S z`p~SzJnB7Iho4~~ma;sz;Zjrwuc4OyEmX(*u^fMa>c`3Gb>4t9)?fE#2s^X_S;%Ud z+mXqbIjDxbs0$aP9?DkKQm(SDM|ISJTDccd=XcxsJJ#cTOC+G&r!jk@k2Y5+%3Gy4$r{rD6$feWbiu3!vaLtPg$ob}g;ds9%y z{ZSpHVGDl)a&Rv7?IWTMUqr4ou`XjqVLEDHsAnPz)nO6N#CfQhZb!{*H)_UV)QnG{I{rN_!waYZdNZOQ ztTyCsnh@&zo($Gs4IE{MM*0crg0rX&E~4(?Rn$OZ`D|$beQ+c8M;+gVI^K<=F^pQ# zv#56df-Ii7gp)93Wb{*A5u~7R{~FXlHlaqg2lcufKo@?Dx;2;V@z_y(=c%WnI_SX} z_%6m_TxN77`=Htzikje9)C9((Zdq^&1tw=!pc?8zeF?i!7rcj>;jge4oR`hr$>bhO1>)t@E=swi-A7DQI1{rA3T%({7#brllkc6A5SEEk+0w>^5)^$40 zLmzI%ap)YwR}Lp*0=A(#T7{a>TCBiL_V}MMp8DT0k^ap^3jAF#-ymOI(|>Gq>GM!a zIRkrR1tww@YQVL&-iUhW0;n(DQ}*~vs9X9v>Y+Y{y4Al!4d5Im)4w@ycU-}nsOufk z2~N~ZQmupSeiv#$nW!0$v-OFn0Zv6HR-oFcK@Dsn>RD(-yO>o^cyScGc#KGZYOkgM-Mg-6+;rE14m z+=hDkJ8gX*s^debfxL(6;Mb@boARD(OLyHNvs6E&bis1Avo{73%*Q2 zBi(0r96<;54Mg|uWzs;j>6U0)O!P_?kr`wWxs$kvw!=iPs5aeBZTi?$kQi0I+k$2j z6|dc)d$Wz`gHl7deUYt$->syLJW0~Y6GSr^Nwnz|Ttajk77}gWi(-C+`bH$#`Vp(X zKauSR{Qk`D+=ty{KhZtDi)4|p7HZDmou{hj`8Df;o+Nxh!TB5r$ZKE6s)$ZWEm%q9AI zt|gJ@PtQO#*-QG7E^>WyQdm#&$wNf%bbs<3(Kd|akV5h{;j56By+EgU8CdpEz& zko)YuAEU01Y{~pCwdIGc&7t;whn?BYEv`EEl0aii^XTx@S(6ZPaXsmPjJoSw}PhG&D7d|oYpE2=^np)}}4(}UW?uhj?1j1L-HaOya zjoya>;k82tIz}eWxu+_()aT*amgd|tcfeEPD$Fk^%*`*(EtudcC@v|O7&<>}h?6}N zatn%F`NbuLq2%F}>6O!Fmsd|KpYEDmSvj?-F|WnvoswATZuYjiy);ti4s{NnAL=z? zbSQsBcXGDh)9m-SnwmUbPjkI{bofsrmiLM)_4w*SRheJsYaaC;{`mvPyIo5>K39{+ ze|;`>49y>%;_g0eAT8+!V+E E0qjZD3IG5A diff --git a/feincms/locale/ca/LC_MESSAGES/django.po b/feincms/locale/ca/LC_MESSAGES/django.po index 86ea7b459..645d74bc3 100644 --- a/feincms/locale/ca/LC_MESSAGES/django.po +++ b/feincms/locale/ca/LC_MESSAGES/django.po @@ -1,33 +1,33 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: -# Maarten van Gompel (proycon) , 2009. +# proycon , 2009 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: LANGUAGE \n" -"Language: ca\n" +"Language-Team: Catalan (http://www.transifex.com/projects/p/feincms/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Language: ca\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "plantilla" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "ordenació" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "idioma" @@ -35,7 +35,7 @@ msgstr "idioma" msgid "All" msgstr "Tots" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Pare" @@ -44,50 +44,50 @@ msgstr "Pare" msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "títol" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s ha sigut mogut a una nova posició" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "No entenc l'odre de moviment" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "accions" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Segur que vols esborrar l'element?" +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "contingut de l'aplicació" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "continguts de l'aplicació" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplicació" @@ -144,65 +144,45 @@ msgstr "arxiu" msgid "files" msgstr "arxius" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "imatge" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "llegenda" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "imatges" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "posició" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(sense llegenda)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "arxiu de medis" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "arxius de medis" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "bloc" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "esquerra" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "dreta" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "tipus" @@ -227,19 +207,17 @@ msgstr "Ignora els avisos de validació de l'HTML" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"La validació de l'HTML generà %(count)d avisos. Per favor, revisa el " -"contingut actualitzat de la part inferior abans de continuar: %(messages)s" +msgstr "La validació de l'HTML generà %(count)d avisos. Per favor, revisa el contingut actualitzat de la part inferior abans de continuar: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "text" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "text ric" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "texts rics" @@ -247,9 +225,7 @@ msgstr "texts rics" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"El feed RSS s'actualitza varies vegades al dia. Els canvis en el títol sols " -"seran visibles a la plana inicial després de la propera actualització." +msgstr "El feed RSS s'actualitza varies vegades al dia. Els canvis en el títol sols seran visibles a la plana inicial després de la propera actualització." #: content/rss/models.py:22 msgid "link" @@ -283,27 +259,27 @@ msgstr "secció" msgid "sections" msgstr "seccions" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "plà" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "títol de la fila" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "títol de fila i columna" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "taula" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "taules" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "dades" @@ -315,23 +291,21 @@ msgstr "plantilla de contingut" msgid "template contents" msgstr "plantilles de continguts" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "enllaç de vídeo" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Això ha de ser un enllaç a un vídeo de Youtube o Vimeo. Per exemple: http://" -"www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Això ha de ser un enllaç a un vídeo de Youtube o Vimeo. Per exemple: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "vídeo" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "vídeos" @@ -352,9 +326,9 @@ msgid "published on" msgstr "publicat el" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"S'establirà automàticament quan marquis la casella superior de 'publicat'" +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "S'establirà automàticament quan marquis la casella superior de 'publicat'" #: module/blog/models.py:39 msgid "entry" @@ -369,12 +343,12 @@ msgid "tags" msgstr "etiquetes" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "tradució de" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Deixa aquest camp buid per les entrades en l'idioma base" @@ -391,27 +365,27 @@ msgstr "data de creació" msgid "modification date" msgstr "data de modificació" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "tipus de contingut" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "data de publicació" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "publicar fins a" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Si la deixen en blanc l'entrada estarà activa per sempre" -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "visible de-fins a" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Publicació segons la data" @@ -439,19 +413,19 @@ msgstr "meta descripció" msgid "This will be prepended to the default description." msgstr "Això serà afegit a la descripció per defecte" -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Optimització per als motors de cerca" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Editar la traducció" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Crear traducció" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "traduccions" @@ -466,63 +440,63 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Previsualitzar" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "tamany d'arxiu" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "creat" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "tipus d'arxiu" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "informació de l'arxiu" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "" @@ -530,7 +504,7 @@ msgstr "" msgid "parent" msgstr "pare" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -594,23 +568,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binari" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "descripció" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "traducció de l'arxiu de medis" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "traduccions dels arxius de medis" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Aquesta URL ja està en ús en una plana activa." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Aquesta URL ja età en ús per una altra plana activa." @@ -618,76 +592,78 @@ msgstr "Aquesta URL ja età en ús per una altra plana activa." msgid "Other options" msgstr "Altres opcions" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "a la navegació" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Afegeix una plana filla." -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Veure a Lloc" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "heretat" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "extensions" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "és activa" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "actiu" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "URL sobrescrit" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Sobreescriu l'URL. Ha de contenir una '/' a l'inici i al final quan es " -"tracti d'una URL local. Afecta tant a la navegació com a les URLs de les " -"subplanes." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Sobreescriu l'URL. Ha de contenir una '/' a l'inici i al final quan es tracti d'una URL local. Afecta tant a la navegació com a les URLs de les subplanes." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "redirecciona a" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL de destí per les redireccions automàtiques" +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "URL en caché" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "plana" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "planes" @@ -703,28 +679,26 @@ msgstr "Afegeix una breu descripció resumint el contingut de la plana" msgid "Excerpt" msgstr "Extracte" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "extensió de navegació" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Selecciona el mòdul que proveeix les subplanes si necessites personalitzar " -"la navegació." +msgstr "Selecciona el mòdul que proveeix les subplanes si necessites personalitzar la navegació." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "Extensió de navegació" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Selecciones les planes que es mostraran com a contingut relacionat." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Planes relacionades" @@ -765,10 +739,6 @@ msgstr "Títols" msgid " By %(filter_title)s " msgstr "Per %(filter_title)s" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Cercar" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Segur que vols esborrar l'element?" @@ -787,8 +757,7 @@ msgstr "Impossible esborrar l'element" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"No puc esborrar l'element ja que és el pare d'almanco un altre element." +msgstr "No puc esborrar l'element ja que és el pare d'almanco un altre element." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -799,14 +768,12 @@ msgid "Really change template?
All changes are saved." msgstr "Vols canviar la plantilla?
Tots els canvis es guardaran." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Vols canviar la plantilla?
Tots els canvis es guardaran i el contingut " -"des de %(source_regions)s se mourà a " -"%(target_region)s" #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -828,19 +795,21 @@ msgstr "Abans" msgid "Insert new:" msgstr "Inserir nou:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Regió buida" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"El contingut de la plana pare s'inserirà automàticament. Per sobreescriure " -"aquest comportament afegeix algun contingut." +msgstr "El contingut de la plana pare s'inserirà automàticament. Per sobreescriure aquest comportament afegeix algun contingut." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Afegir un nou element" @@ -976,13 +945,9 @@ msgstr "%(comment_count)s comentaris." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s digué el %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s digué el %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -999,6 +964,3 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Gràcies!" - -#~ msgid "Symlinked page" -#~ msgstr "Plana enllaçada" diff --git a/feincms/locale/cs/LC_MESSAGES/django.mo b/feincms/locale/cs/LC_MESSAGES/django.mo index 878c04c4a07d42db035ce17ea1ecd4607e12e249..960bb25a7c1621966529123a8cccb163896f507c 100644 GIT binary patch delta 4125 zcmYk-2~bs40LJn2L;+D0P;)^85kUoohk;g-OQxu0DX6Gv7zkv6RDhM{O-oZ#!BA5p zmox(tTwZCJV>Q__HnvPOjAPogOrvQw6>XD~{l9w;O=sqNzjN=q_pJB6cc`$Yz&Rh) zc9WqTBfZJxcEW-=YOV*zRaK}4u&(23=EBo#HBhw8Wl)$n4}7A!~2a2xi*9oQ3(VFotgZ0x|r zx~>S-(F69l65S<7wYv%*!m949zed=mhd0tN%;7i+HG?7?jr(y0UcqE6r*}W@!XfxM z=3^U1mxhHn6t|+gg{T2E;duNSN8rF{)}Oj5sIB?L>YTBaZ&3~YX#Ev6^S@9dHhsJsJ6U_68jeHF zED6=Ya8$>c)-2QtWusPj0ct|akvG~g>#3-N9mp$d8c+?rg<9g1s2`d$sD{s>I=+DF z_-EAh|Jd(?uJRYWHNeTJ24`a%%tPImk6N+&P#u?}+Fy(-e8#Lphdxc0zQ*uonKWd(%_P)}ic#N} zA**YuFcBM2d-?_HHN1=(*!6MV0EVIll!2r0X4HU|peC{$)!y1T_J0(WeVoX}OZI}X z{Eq6v$*AA7je6GBpeDE_-tkWC z+LGAHX)J#JL7;__bL9NUks2{8n)IgSD zJKT)?Xd0*1o;ZTq>*J^qo<;pKUcnjIexNs?d8m$yt!1dKc*GvB#&sNTz_u7O$h$8d zwNgoV3zlM*-v0(F_jBTROvZbY_+7>-Ou;wsUc88m#oW$CH(&*7Ap1}=JB&H_0gk}l zgT04rCTb-Xp|<8Z)W8}sl>SY?tuS-cQon~m+n&8UuQQ6t=qp;%`v39?xifU*PYGzCA z@k&&~>rhL*2Rmb<^#pe0_+#tYRMuY?T;N0m{)t+`_I|H}9;gAvSo@sFisX_5E7Z1U5KS)bSS7>sF7t@g%CF(-?%!s2k3r2J{VTpcm}< zKTvPMKj_2#BtZ10tR&A7UNEzS+)46@w#-?<$99rQR0epso!m}+0?|xci{9M>L=Wx; z@(|H$r;<%JlADQsj#V?AzH?k`?3jwh|}{+w(%N=qPfK+(#yn&P1gzDI&{tK&kZj@AFk^546s?(4L-;4J6GTizi6|sUT~~ zWU`6OsF~NXOHEnFwu-ZgGmS*=Oeo1Ew-J@+$was2{j-$W`do~+^?IB_rjg+!k8C5c zoI=xf8X9k{Rnx5MA`E@@HMiFq>%NbA89Q;sq`l!$x_md#1WMd z-XQ}PYdjiecTtwh|38H)C?^41(K7#3<^Z1P;*j``f4)MTK)xI C#e>%X delta 4372 zcmYk;d303O0mtz>WS1-^Bq5XllQ2L+2xKsX6bLF%AYcL6WD#LVCJPCfI1B+IbVP}D zsZb3FxCA3o3KbDXqY160BpkaO<&UZdtJXpff3(=17D`L&InwWM-c9X0`OW9vH}Bo; zEtB@@Q#Ik=XT80PP>^{O5Kf)q|XC-b2mgQ|!P$p$70c)6j9xVmTf{ z4e+Af{{_yV{v~R~CS*GU4522p9o0@7hD#~zq2R_oRKr(L9bZE=to7F=NZ>;=9)a5L z!Ea#^Y67#d4Abi`I;z8)wmu-o=_etF^;big>G*m?}L0w+-e?n0f{XZ--x?nTtZE}`20tMxiEfUvpg6im!;XUS4gOFjxUvkK&0 zVJcA_twJ7sQ-^A>6}9AH)O%zvYGwye12~Ktz-y@EyY2VyVw|4;Us2FZE<|@2^D*kg z&rl6tvETm(H4xVbXMYB2#$!+&cu@nMZtL@G{XSItRj3u*fVw2jm>8z8)$Z7ddUZa5 zI`9DM#17QRkDvy295s*#Y9;#Y_aCFq`xG^>OQ;E4MYXGETmwx*wU>+G0Tl8m=tK`{ z>Bgcuo`mXP8n(HNS%55p`7n>yE?!6OQB!YJYj6xcgwdx0^_ceL zv;G?4m+TmTE*^S~EEey=B-Fs>p=PuQ)!-`o{Z?E-z1x1D;c<@3Mg10xM$Nbkt8gZ2 z<&GkYV&3tDonNVo?9j;mf$C`BDCb&cq26eDsGDyEYKAqo-h|E6x7+=HL0zI77>8fu zXpH4U`-@PQq7-M~%rJ!#3Xh=%@HT2iKCu1~wbVC}A1ss3I_^aes=;p549{UDUch)9 zQs7)VH_oCy5$E9+Ou%!fOCA0-1>LnD;kWS;YH5ZRI&ZY8r~xfR&8QlA+nNowz6%qn zKZ&~L?WlpCM!iAL<9+xC)WFKeIs>@VF>K~g&^1|TzgUM)Q?J8V{3mLKzCtxHuE<%s zJ8(Mn7MzQ3VFP}R<8T8X^lA3v1pEcA$G;)|sddDp5>bN(V`RloP#g^lo~9XyXZvZu|M{AUnuYgr6hxeWLO6ixAy()mn%ydrfo?Z(ZwS zIF&VsuFy6rXYCjLtfBBaIZfUnC&^nxEBHM!hTKDr6D^|d)qSLYdxF9g5+U2k7NTt{ z$tMluHNAth6*xpc2iS5Dwff!U6|#aXAbO*&C5Oq+N&j}r7T(4O$xEb;JWX`DYY7i? z^jG^u)Wh_=?cY33h5via&qx`WL@LNSqHQ(_k!9pnGM4mjehQ1o!=##M>u>j7${WdM z@*H`YJVPqUk4f<(eEk3RBPwpPlC+VZl0&42Om6Q?9TfIbnnko7a4-+yLR&tAy505u ze$wvq;3iw{XD5XcGK1(vF^b$z-X-m1J<%3R_C!m@eCL~)IeSKfo>6UC06ktGlVUv$bV&VWc*1 zSwiCSZFPfD-LCkS=Af@7&_3LI\n" "Language-Team: LANGUAGE \n" @@ -17,16 +17,16 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "šablona" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "řazení" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "jazyk" @@ -34,7 +34,7 @@ msgstr "jazyk" msgid "All" msgstr "vše" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "rodič" @@ -43,50 +43,50 @@ msgstr "rodič" msgid "Category" msgstr "kategorie" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "změň %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "Název" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s přesunut na novou pozici" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "Nesrozumitelné přesunutí" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "akce" -#: admin/tree_editor.py:429 +#: admin/tree_editor.py:432 #, python-format msgid "Successfully deleted %s items." msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, fuzzy, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "Obnov smazané %(verbose_name)s" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "aplikační obsah" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "aplikační obsahy" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplikace" @@ -143,67 +143,47 @@ msgstr "soubor" msgid "files" msgstr "soubory" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "obrázek" -#: content/image/models.py:46 +#: content/image/models.py:48 #, fuzzy msgid "alternate text" msgstr "šablonový obsah" -#: content/image/models.py:47 +#: content/image/models.py:49 #, fuzzy msgid "Description of image" msgstr "popis" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "název" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "obrázky" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "pozice" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(bez názvu)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "mediální soubor" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "mediální soubory" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "do bloku" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "vlevo" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "vpravo" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "typ" @@ -232,15 +212,15 @@ msgstr "" "HTML validace vyplivla %(count)d varování. Prosím zkontroluj obsah níže před " "pokračováním: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "text" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "" @@ -284,27 +264,27 @@ msgstr "sekce" msgid "sections" msgstr "sekce" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "prostý" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "titulní řádka" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "titulní řádka a sloupec" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tabulka" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tabulky" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "" @@ -316,11 +296,11 @@ msgstr "šablonový obsah" msgid "template contents" msgstr "šablonové obsahy" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "odkaz na video" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -328,11 +308,11 @@ msgstr "" "Toto má být odkaz na youtube nebo vimeo video, např. http://www.youtube.com/" "watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "videoa" @@ -370,12 +350,12 @@ msgid "tags" msgstr "tagy" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "překlad" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Nech prázdné pro články v primárním jazyce" @@ -392,27 +372,27 @@ msgstr "datum vytvoření" msgid "modification date" msgstr "datum úpravy" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "typy obsahu" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "datum publikace" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "konec publikace" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Nech prázdné pro články, které mají být publikovány stále" -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "Publikováno od - do" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Publikování na základě data" @@ -440,19 +420,19 @@ msgstr "meta popis" msgid "This will be prepended to the default description." msgstr "Toto bude přidáno k výchozímu popisu" -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Optimalizace pro vyhledávače" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Vytvoř překlad" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "překlady" @@ -469,63 +449,63 @@ msgstr "" "Nemůže být přepsán jiným typem (pokoušíš se přepsat %(old_ext)s s " "%(new_ext)s)" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." msgstr[1] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "Přiděj vybrané mediální soubory do kategorie" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "ZIP archiv exporotován jako %s" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "export ZIP archivu selhal: %s" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "Vyexportuj vybrané mediální soubory jako zip archiv" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "náhled" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "velikost souboru" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "vytvoreno" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "typ souboru" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "info o souboru" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "%d souborů importováno" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "import ZIPu selhal: %s" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "Žádný vstupní soubor" @@ -533,7 +513,7 @@ msgstr "Žádný vstupní soubor" msgid "parent" msgstr "rodič" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "" @@ -597,23 +577,23 @@ msgstr "" msgid "Binary" msgstr "Binární" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "popis" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "překlad mediálního souboru" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "překlady mediálního souboru" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Toto URL je už obsazeno aktivní stránkou." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Toto URL je už obsazeno jinou stránkou." @@ -621,50 +601,55 @@ msgstr "Toto URL je už obsazeno jinou stránkou." msgid "Other options" msgstr "Další nastavení" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "v navigaci" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Přidej podřízenou stránku" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Zobrazena na sajtě." -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "Originálnío překlad zkopírován do nově vytvořené stránky." -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "Nemáte dostatečná oprávnění pro editaci tohoto objektu" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "zděděný" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "rozšíření" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "je aktivní" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "aktivní" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "vynucené URL" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -673,23 +658,24 @@ msgstr "" "Přepíše cílové URL. Ujisti se, že máš \"/\" na začátku a na konci pro " "lokální URL.Toto ovlivňuje navigaci cílové stránky i podstránek" -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "přesměruj na" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." +#: module/page/models.py:178 +#, fuzzy +msgid "Target URL for automatic redirects or the primary key of a page." msgstr "Cílová adresa pro automatické přeměrování" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "stránka" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "stránky" @@ -705,12 +691,12 @@ msgstr "" msgid "Excerpt" msgstr "výňatek" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "rozšíření navigace" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -718,15 +704,15 @@ msgstr "" "Vyber modul nabízející podstránky pro tuto stránku jestli chceš upravit " "navigaci." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "rozšíření navigace" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Vyber příbuzné stránky" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Příbuzné stránky" @@ -767,10 +753,6 @@ msgstr "Titulky" msgid " By %(filter_title)s " msgstr "" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Vyhledat" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "" @@ -829,11 +811,15 @@ msgstr "Před" msgid "Insert new:" msgstr "Přidat novou:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Region je prázdný" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." @@ -841,7 +827,7 @@ msgstr "" "Obsah z nadřazené stránky je automaticky zděděn. Přidej nějaký obsah, který " "ho přepíše." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Přidej novou položku" @@ -998,5 +984,20 @@ msgstr "Odeslat" msgid "Thanks!" msgstr "Díky!" +#~ msgid "(no caption)" +#~ msgstr "(bez názvu)" + +#~ msgid "block" +#~ msgstr "do bloku" + +#~ msgid "left" +#~ msgstr "vlevo" + +#~ msgid "right" +#~ msgstr "vpravo" + +#~ msgid "Search" +#~ msgstr "Vyhledat" + #~ msgid "Symlinked page" #~ msgstr "Propojená stránka" diff --git a/feincms/locale/de/LC_MESSAGES/django.mo b/feincms/locale/de/LC_MESSAGES/django.mo index e189f76159e9abaeed7e0585c6c551afbe6d39c1..deda58df15ab1ad566239c7d02f504aaba3f9d26 100644 GIT binary patch delta 5871 zcmZ|R33OD|9mnw(*(74ZE=!ch5+?yBlLQhVf-Dji1wn{{VhWSwWoF3aO*(HT!KfWk zQBkDm6Hr_#71z2)km7CxaTjfomTKj+^&CAOt3uDIZLR(OG8b)oj_>f#=iWQ--TS}G zo8jTsEo(9#_3ysf;yO$e5XX92R$-21y?L@)Eo)VO0>d~6U&i5h2>anN9D_XvSXMV2 zhf^?w>Mw?Qcn#{g&DaN@K%UE3&r`^!;ZN8DkD@yI2FvhU(;gbgAk-_2Q}Gn)XJIa` zFzt;gXWy&-#=<0sIc>%L;Jw z={OZNqk8O%E!Yd!;z_t3_1tDu0?(l)vJZPOzV#LbW%NF#@I&m5OPHQIT865x#L?J* zTB++$18l@$xD6-bPOQMsP%CQ>$tGNi+KOsZuffbv8e$YQgR79$wl<+wWCz}bPofe$ zkDGPh3Y?5l)J(RU_6Kkl^_{4t|2t{|)5uOUuSWHAE^fo+!&rZ1e3S+aT*L{naVlz{ zT2vydQ3I_(CS_$%9c@Le%yy&;>po;m>m{tj!?*(ba}sr*i+av8^~(!be|>Nz4I1!T z)Ihgj5^u-TFz?jtOoFKUD@?r#YpBn{*|-&F;vaAwp2oxDaR=%!AHWjqHiGkl_5d<~27TT~(eJG<8k6bKQf#6a8!SzQDhsJL3R?PV9EcYp=g)Fcd$$htdfkZH!&{BpQ3*YS+M=gX_wP0Jw~U8TOa7_({HSUF zC$f?mtM{mECV8l(9cCPXI^|7xfJ)$?@d#=KKSymzH{Mw-^>EbpLjcwP zWbDWI)*K4zXgO*NYOxz8Q60CU240IA_EqaJ(XJ8nx#` zin6~6A=DSq1*q4$1^E)Sc3>}j4!h&t4282PypBC^5WOnH;i!Q|p%N)Ub+7zASOH#zr(>?(|A#2(ft}d~>p9et?nf=r z7pOfxib~`JveU2INSubtP&3<%IurMz?%#t-_%$Ra>j-MkPcF$$cm(#<`(H`n0X~?E zdH5yv!SC=K>=Vkqugg&bG~yh*)c7)TnIyHRK00o0*<3FqMlI1_DtNVFw&n2#}3Vwa${;7aU= z*P-s)hMBb#wo}kjjpnFopfgYdpM|<{9_sB_gtKrXF2n=q|)crq4J%0ykyn8aH;ZalvJB=@(5_`>jegKvEA=CZ|s^c$E&mBVz z@NZNCCr!ydKM*xw0cuM}n|cxIzD&q8Oh$D$9W`(@>X0o&Jy?%gi70AjYj6l&jate( zQ3>uw9kP9@z@Mi!WQEh<6B=o;IMS72|w|LZAeARjf*t*Di_3pJw$Q60aCI@Je|rL#UpJ@;qS zbDyG~`zvat{(<_!%HcnXIcO6!S-&OTA)>^TIsDxp(K(- z9r39D?a3o%?xmzRT$jG<-XpZTy6zw@AYLTGgsx>oiU<(e#C!ePyy2PGDcwf!mRna6 z*AQC>T?Yt#cZ?u5679rVVkeu&`61v6_!wK!=YlN<|iT8<@h^L8qqM7&=q3h}_U4L)l?-QopXyim&&l1<^2jw7z zO+qc!|5Nt^B>1 zm`98vd_va>;`hYks&I`VE+@`Yg=;)BL*6ejyeS7cDRi zKgC>Az8R0VnK%)B3k}^A8RhTNrmzj_o;dr#|I0*o8%{ zPO>iHIV;_8v$L`#o=%42#a_p^gKB$ri=`ZYdBKB&BaxUJv1*((DXS(LcALDB==ggE z4Vz@Al3~}2hf}eHYe&PLUFSHiU7u))(RnIir=pJSI&JYw?E0h=)`%_Ph*Q$B;MC`P z&6(rG+_M%g&0XTOB$BD%LN5|)2+m4JykJeD%8sT|EmfgVB$kS%>q_bq&7nr_uW$Cg zH|BY1$MZ`Ihi1x3gXI-=Sy@$C`MA>Z($d_;i-Jp>)|f|L!PyL4WtW$hO$cW1E1gnR zRxz%WD|bQIO9gApBofIgdto@0ipH49IgXcd+-M@+ZclA)nxVm?PApYYA3c+&+(?>< z1Z$jdbCo@JhLda#yLOSuxvj0Oq-$Yfjn0~`)LW8?)vUM|YWY6$+}9#+*7D+ngk~ zme@swMTvOBN;baOvm4UM`X~p6?aa0mm-rVKzv7=ccJh>&X)ofmb?%79Ib1(-rtEm< zF0yc3YgR1Y5O*Su+u-;&j@>XYIFp`Zt+um9=OD&3+>(yMag%epJ8iLuUpM~49J^zB za79jLX^TU?PSUj-lAX`iH#zQjJKbzI#2nADFJKBfhFvw!UR1Z*X-au^o93P5q4qQz z8jq8}k95rlO?v5*sS#aoU8$3B9V_hIqpB{EZc(a!UNiD{;wN=P(vYyOHdX9PgJ_j`lCCEF8+fcA@vf;UMXY<}bGAH~SY?7Wj`< b4$hm&sY|+i2eqa+s{Y57LpnaMoYDP1>(GN` delta 5652 zcmb8ydvH|c9merP2?Qb%BtYbTxC9cyh9q19;g*C12;>4GK?zb=l9SEKW;gC`xTm)IVIMda#GCEn-o~u=ASw+1qYXuf#Uwi}y;>&mq9>T4W?>EuUX z3QjfUvyrh_l~{@^(2I{_H%w+0-LV&@(!Vu;geE%%`{874!fG6X`%w*^K>k_h_@FK8 z3XZ}wDrrWA*bC=iGG32Y;R+m$0n`BQLrvsC>_Y$6VB!BcN6B|0c^l?n2!}hEo(f+ zVkELiw4(-a3bnUqPy_oK=inurhBNKNOm9Z5#7@+qd=7OMj-i(PeN=lVQIFqg)c5~J zt@ID5GZ0H1mN@kzQ5C169;aETJ*zTahZ@id)RwfM?%!bY8;#pgOT62B|FkK89<_pp zQ3E-e$j7Yr%oit6GyfFT@M+^YQ~n>5zla*(71RK`4^K4Q8`W{TahNe1)$T;picB^6 zl6XF5S#wEfM%AbWmKlAh4sJrtd_8Ign@|JTY}|=FvDPD~EjfUi;rpof!6{Vx-=f}_ zmr?EXp0#wIEs0x+l`x?}YmZ4_UVDdMj>b0WwcAfctD{3Iy zP5Be3iN1m{b#RP?M*IOP|GCM3gX-WCs=^i20K1J$Y*8Aj!-1#)jx^<2s6&^B8fX!! zo!OX#m8g0(BYFNcvZWMgX#(bkTTvA^qB_1CH6s_*@KdOPzJy756n}wlqUybk8t4b8 zj!&W5KZ8Y`EbAi9AYU+w_1B)Q9%WfPy4F_IF^hg*0V#@+9`$gWA%WsDanvQ`m$(_4}X7G2B%P4kTxOl`@ax_pz)9IvdQp#ae(mTrE#^4}USquNQCl6VYL zu`~J6sQa@~D>5DRACS4ofMV7SB-G(b)J%e?j@nQ&*l660{m5@e4RjBxp@YWvO!*n? zP5A{>hshjuwci_6ZwP8db1+HI|6~$cn(3&enPqO6AHRVmGv)QDGqTd;Bd7sxFy3L@ zV%&l1Xg6wQo<{ZaENWo;u%Dj)!z9%3N7xh3qL%I=s^Wi96@Nrk>@qd6QoXPb`E=w* zE&dwUKgx(!PmEl@TXi?gg z;rdkq>up?5cuc+)*ATxk`AYPebP+y4+?mJ^xAr9x@jqrBH0c6dZqmctDXHV8M9Hl) zC68e_aSx$W_b{Q;)^WW`;wEAaG2DGPH7({Pb&%jM1?zc2PwN)qNkUgPF_6$szCq}k zN4!rQCSD{~603-(30=1*h=2Z;&*x0O(a3?Y{zCj(Kb7N1Y$aNV14PHQfW%aHVXw6Q z&7>v}PZ2f5-Gr_a?k&C2V|tSxC0-*wAawBz#jovr-ayPHMiAQwT}z2ih-a1I8cA#* z7AnIvmN-fLnRtT8A#_zGi2u5bCta4A zkzvZ7G2V}Q8%!iNnX-J`Ogv6ZBkm>sszay$624CCC#s1$Vh5osLc9=9@s7j>Vk41C z3?_69AeIqt5@U$Ygsw-3uJM#*{SrqJZxJ68ONdOOzJd>3AtEK7;`a|b%1x1VoWv`{ zYE$rgyo=aP+-%BjY+u%UedocU)^&D6C>V8uQM)M|YO$lujvWg7eg2>~;GXC^wmqv~ zeOLFcK~K&P`<$p#|1YMZ^mRgq!sI|d(0u3S(&Yku*ZGJA1Z&7$(^s+1b1H586|DkDCB zqo<_J7xC1F3hk5y)wP~kVTaB_K~JeS>J-}fxq0I~x%r;FNp@~-VQy}AZl3#EM&H&~WwocY*q&QmSXrK3UtLv}QsIq6J+)zPFcR=aL*YVuc3nkv&rV?TX^6IdvN1w2F$NfIlY`_WgVhL#r&WEb}aO!V!j6 zXy>`NkDBjx8GSyvD%8;2!uowb`VMz`X8-obGCiG|=X--eJJ=SseF4Ycz%pwt{^+_^ zCuq}z6J1Xtb2Z7fhUTbaJN}@Zkr@g!E@$PkB6f>EsxqgA(x9`(l&){Hj~rY{rH1CP z<6r3nv)sHfM+cV&o4tXky(-kw>UY94ygC%Lt2_4f!k8)PC61}m7WCPTPQ)(p2f%I0 z-rU1>)@m!_HQT$6o!qI5zoo?qyCt4e?RL)6PO(zI6LD-ab9yP7O|&AqTx``HzOl65@MLn^04D$%OdW!+yU;M+)aJvIDsSk zS&t}VEDJa-dK}#GdF9s>2iS>@d1?(Q9qvAmceej*hXwN4D;;lmCEMsktwl~yQ*rm^ zPjJuY7cNP(;|z1RjBjecFh2B)PK(?dCk=PEO!D=w(_Kdn^3mwnC2Tp9@%yOj4lWqcHU8ZA z-J*hw%%8S4YI_3_J0oJ%moM;?w`jv{x(>AY>?Wr<;BG4znyQDEbL51BJbtU4_Cp2N GC;bl{t3CMu diff --git a/feincms/locale/de/LC_MESSAGES/django.po b/feincms/locale/de/LC_MESSAGES/django.po index 12d8cd5b8..2f3530775 100644 --- a/feincms/locale/de/LC_MESSAGES/django.po +++ b/feincms/locale/de/LC_MESSAGES/django.po @@ -1,27 +1,29 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy +# +# Translators: +# Matthias Kestenholz , 2011 +# sbaechler , 2013 msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-02-16 00:00+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"Project-Id-Version: FeinCMS\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" +"Last-Translator: Matthias Kestenholz \n" +"Language-Team: German (http://www.transifex.com/projects/p/feincms/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:369 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "Template" -#: models.py:509 +#: models.py:510 msgid "ordering" msgstr "Sortierung" @@ -48,44 +50,45 @@ msgstr "Kategorie" msgid "Change %s" msgstr "%s ändern" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 #: module/medialibrary/models.py:40 module/page/models.py:170 #: module/page/models.py:226 msgid "title" msgstr "Titel" -#: admin/tree_editor.py:402 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s wurde an eine neue Position verschoben." -#: admin/tree_editor.py:406 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "Unbekannter Verschiebe-Befehl." -#: admin/tree_editor.py:415 +#: admin/tree_editor.py:420 msgid "actions" msgstr "Aktionen" -#: admin/tree_editor.py:427 +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "%s Elemente gelöscht." +msgstr "%s Einträge gelöscht." -#: admin/tree_editor.py:435 -#, fuzzy, python-format +#: admin/tree_editor.py:440 +#, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "%(verbose_name)s löschen" +msgstr "Ausgewählte %(verbose_name_plural)s löschen" -#: content/application/models.py:217 +#: content/application/models.py:218 msgid "application content" msgstr "Applikation" -#: content/application/models.py:218 +#: content/application/models.py:219 msgid "application contents" msgstr "Applikationen" -#: content/application/models.py:248 +#: content/application/models.py:249 msgid "application" msgstr "Applikation" @@ -148,11 +151,11 @@ msgstr "Bild" #: content/image/models.py:48 msgid "alternate text" -msgstr "Textalternative" +msgstr "Alternativtext" #: content/image/models.py:49 msgid "Description of image" -msgstr "Beschreibung des Bildes" +msgstr "Bildlegende" #: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" @@ -205,19 +208,17 @@ msgstr "HTML-Validierungswarnungen ignorieren" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"Die HTML-Validierung ergab %(count)d Warnungen. Bitte überprüfen Sie den " -"aktualisierten Inhalt bevor Sie fortfahren: %(messages)s" +msgstr "Die HTML-Validierung ergab %(count)d Warnungen. Bitte überprüfen Sie den aktualisierten Inhalt bevor Sie fortfahren: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "Text" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "Text" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "Texte" @@ -225,9 +226,7 @@ msgstr "Texte" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"Der RSS Feed wird mehrmals täglich aktualisiert. Eine Änderung des Titels " -"erscheint erst nach der nächsten Feed-Aktualisierung auf der Webseite." +msgstr "Der RSS Feed wird mehrmals täglich aktualisiert. Eine Änderung des Titels erscheint erst nach der nächsten Feed-Aktualisierung auf der Webseite." #: content/rss/models.py:22 msgid "link" @@ -293,29 +292,27 @@ msgstr "Template" msgid "template contents" msgstr "Templates" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "Video-Link" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Dies sollte ein Link zu einem Youtube- oder vimeo-Video sein, z.B.: http://" -"www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Dies sollte ein Link zu einem Youtube- oder vimeo-Video sein, z.B.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "Video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "Videos" -#: contrib/tagging.py:119 +#: contrib/tagging.py:117 msgid "Tagging" -msgstr "" +msgstr "Tagging" #: module/blog/models.py:28 msgid "published" @@ -330,7 +327,8 @@ msgid "published on" msgstr "veröffentlicht am" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." msgstr "Wird automatisch gesetzt, wenn `veröffentlicht` aktiviert ist." #: module/blog/models.py:39 @@ -356,7 +354,7 @@ msgid "Leave this empty for entries in the primary language." msgstr "Dieses Feld für Einträge in der Primärsprache leer lassen." #: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:46 +#: templates/admin/feincms/item_editor.html:43 msgid "available translations" msgstr "Verfügbare Übersetzungen" @@ -368,35 +366,35 @@ msgstr "Erstellt um" msgid "modification date" msgstr "Verändert um" -#: module/extensions/ct_tracker.py:139 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "Inhaltstypen" -#: module/extensions/datepublisher.py:69 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "Veröffentlichen am" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "Veröffentlicht bis" -#: module/extensions/datepublisher.py:74 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." -msgstr "Leer lassen wenn das Element immer aktiv bleiben soll." +msgstr "Leer lassen wenn das Element ewig aktiv bleiben soll." -#: module/extensions/datepublisher.py:105 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "sichtbar von – bis" -#: module/extensions/datepublisher.py:115 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Datumsbasierte Veröffentlichung" -#: module/extensions/featured.py:11 +#: module/extensions/featured.py:9 msgid "featured" msgstr "Feature" -#: module/extensions/featured.py:16 +#: module/extensions/featured.py:14 msgid "Featured" msgstr "Feature" @@ -420,90 +418,88 @@ msgstr "Diese Beschreibung wird vor der Standard-Beschreibung eingefügt." msgid "Search engine optimization" msgstr "Suchmaschinenoptimierung" -#: module/extensions/translations.py:201 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Übersetzungen bearbeiten" -#: module/extensions/translations.py:204 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Übersetzung erstellen" -#: module/extensions/translations.py:209 module/extensions/translations.py:212 +#: module/extensions/translations.py:215 msgid "translations" msgstr "Übersetzungen" #: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" -msgstr "Dies würde eine Schleife in der Hierarchie erzeugen" +msgstr "Dies würde eine Endlosschleife in der Hierarchie erzeugen." #: module/medialibrary/forms.py:64 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "" -"Kann nur gleiche Dateitypen ersetzen (versuchte ein %(old_ext)s mit einem " -"%(new_ext)s zu überschreiben)" +msgstr "Dateien verschiedenen Typs können nicht überschrieben werden. (%(old_ext)s durch %(new_ext)s)." -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "%(count)d Mediendatei zu %(category)s hinzugefügt." -msgstr[1] "%(count)d Mediendateien zu %(category)s hinzugefügt." +msgstr[0] "Erfolgreich %(count)d Mediendatei zu %(category)s hinzugefügt." +msgstr[1] "Erfolgreich %(count)d Mediendateien zu %(category)s hinzugefügt." -#: module/medialibrary/modeladmins.py:76 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" -msgstr "Ausgewählte zu Kategorie hinzufügen" +msgstr "Ausgewählte Mediendateien zu Kategorie hinzufügen" -#: module/medialibrary/modeladmins.py:85 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" -msgstr "ZIP-Datei exportiert als %s" +msgstr "ZIP-Datei als %s exportiert." -#: module/medialibrary/modeladmins.py:87 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" -msgstr "ZIP-Datei Export fehlgeschlagen: %s" +msgstr "ZIP Export fehlgeschlagen: %s" -#: module/medialibrary/modeladmins.py:92 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" -msgstr "Ausgewählte Mediendateien als ZIP exportieren" +msgstr "Ausgewählte Mediendateien als ZIP-Archiv exportieren." -#: module/medialibrary/modeladmins.py:135 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Vorschau" -#: module/medialibrary/modeladmins.py:140 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "Dateigrösse" -#: module/medialibrary/modeladmins.py:145 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "Erstellt" -#: module/medialibrary/modeladmins.py:164 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "Dateityp" -#: module/medialibrary/modeladmins.py:185 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "Dateiinfo" -#: module/medialibrary/modeladmins.py:197 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "%d Dateien importiert" -#: module/medialibrary/modeladmins.py:199 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" -msgstr "ZIP-Import schlug fehl: %s" +msgstr "ZIP Import fehlgeschlagen: %s" -#: module/medialibrary/modeladmins.py:201 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" -msgstr "Keine Datei angegeben" +msgstr " Keine Datei angegeben" #: module/medialibrary/models.py:43 msgid "parent" @@ -585,11 +581,11 @@ msgstr "Mediendatei-Übersetzung" msgid "media file translations" msgstr "Mediendatei-Übersetzungen" -#: module/page/forms.py:165 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Die URL wird schon von einer aktiven Seite verwendet." -#: module/page/forms.py:183 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." @@ -597,43 +593,43 @@ msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." msgid "Other options" msgstr "Weitere Optionen" -#: module/page/modeladmins.py:95 module/page/models.py:174 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "Im Menü" -#: module/page/modeladmins.py:110 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Unterseite hinzufügen" -#: module/page/modeladmins.py:112 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Auf der Webseite anzeigen" -#: module/page/modeladmins.py:131 +#: module/page/modeladmins.py:126 #, python-format msgid "Add %(language)s Translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:161 +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." -msgstr "" +msgstr "Der Inhalt der Originalseite wurde auf die neue Seite kopiert." -#: module/page/modeladmins.py:175 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" -msgstr "Ungenügende Berechtigung um dieses Objekt zu bearbeiten" +msgstr "Sie haben die nötige Berechtigung nicht, um dieses Objekt zu bearbeiten" -#: module/page/modeladmins.py:190 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "geerbt" -#: module/page/modeladmins.py:194 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "Erweiterungen" -#: module/page/modeladmins.py:198 module/page/models.py:206 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "Aktiv" @@ -648,12 +644,9 @@ msgstr "Überschriebene URL" #: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Überschreibe die URL. Am Anfang und Ende muss ein / stehen, falls es sich um " -"eine lokale URL handelt. Dieses Feld bestimmt die Navigation und die URLs " -"von Unterseiten." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Überschreibe die URL. Am Anfang und Ende muss ein / stehen, falls es sich um eine lokale URL handelt. Dieses Feld bestimmt die Navigation und die URLs von Unterseiten." #: module/page/models.py:177 msgid "redirect to" @@ -661,17 +654,17 @@ msgstr "Weiterleiten zu" #: module/page/models.py:178 msgid "Target URL for automatic redirects or the primary key of a page." -msgstr "Ziel-URL oder Seiten-Id für automatische Weiterleitungen." +msgstr "" #: module/page/models.py:180 msgid "Cached URL" msgstr "Zwischengespeicherte URL" -#: module/page/models.py:393 +#: module/page/models.py:395 msgid "page" msgstr "Seite" -#: module/page/models.py:394 +#: module/page/models.py:396 msgid "pages" msgstr "Seiten" @@ -687,12 +680,12 @@ msgstr "Kurze Zusammenfassung des Seiteninhaltes." msgid "Excerpt" msgstr "Auszug" -#: module/page/extensions/navigation.py:83 -#: module/page/extensions/navigation.py:108 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "Navigations-Erweiterung" -#: module/page/extensions/navigation.py:111 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." @@ -702,17 +695,17 @@ msgstr "Wähle das Modul aus, welches weitere Navigationspunkte erstellt." msgid "Navigation extension" msgstr "Navigations-Erweiterung" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Seiten auswählen, welche als ähnlicher Inhalt angezeigt werden sollen." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Verwandte Seiten" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Seite" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" @@ -720,8 +713,7 @@ msgstr "Verbundene Seite" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "" -"Der angezeigte Inhalt wird durch den Inhalt der angegebenen Seite ersetzt." +msgstr "Der angezeigte Inhalt wird durch den Inhalt der angegebenen Seite ersetzt." #: module/page/extensions/titles.py:13 msgid "content title" @@ -737,8 +729,7 @@ msgstr "Seitentitel" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Seitentitel für das Browser-Fenster. Standardmässig gleich wie der Titel." +msgstr "Seitentitel für das Browser-Fenster. Standardmässig gleich wie der Titel." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -778,13 +769,12 @@ msgid "Really change template?
All changes are saved." msgstr "Template wirklich ändern?
Alle Änderungen werden gespeichert." #: templates/admin/feincms/_messages_js.html:9 +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." -msgstr "" -"Template wirklich ändern?
Alle Änderungen werden gespeichert und " -"Inhalt aus %(source_regions)s nach " -"%(target_region)s verschoben." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." +msgstr "Template wechseln?
Alle Änderungen werden sofort gespeichert und Inhalt von \n%%(source_region)s nach %%(target_region)s verschoben." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -808,7 +798,7 @@ msgstr "Neu einfügen:" #: templates/admin/feincms/content_editor.html:15 msgid "Copy content from the original" -msgstr "Inhalt kompieren von Original" +msgstr "" #: templates/admin/feincms/content_editor.html:19 msgid "Region empty" @@ -818,9 +808,7 @@ msgstr "Region leer" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"Inhalt wird von der übergeordneten Seite geerbt. Füge Inhalt hinzu, um " -"dieses Verhalten zu ändern" +msgstr "Inhalt wird von der übergeordneten Seite geerbt. Füge Inhalt hinzu, um dieses Verhalten zu ändern" #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" @@ -829,7 +817,7 @@ msgstr "Neues Element hinzufügen" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "Nochmals %(verbose_name)s hinzufügen" +msgstr "Weiteres %(verbose_name)s hinzufügen" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" @@ -873,13 +861,11 @@ msgstr "Startseite" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "Gelöschtes Element %(verbose_name)s wiederherstellen" +msgstr "%(verbose_name)s wiederherstellen" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" -"Diese Version kann durch Drücken des Speichern-Knopfes wiederhergestellt " -"werden" +msgstr "Speichern drücken, um diese Version dieses Objekts wiederherzustellen" #: templates/admin/feincms/revision_form.html:12 msgid "History" @@ -888,12 +874,11 @@ msgstr "Verlauf" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "Alte Version von %(verbose_name)s wiederherstellen" +msgstr "%(verbose_name)s zurücksetzen" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" -"Diese Version kann durch Drücken des Speichern-Knopfes zurückgeholt werden" +msgstr "Speichern drücken, um zu dieser Version des Objektes zurückzukehren." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -930,8 +915,7 @@ msgstr "Kategorie auswählen:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" -"Die folgenden Mediendateien werden zur ausgewählten Kategorie hinzugefügt:" +msgstr "Die folgenden Mediendateien werdene zur ausgewählten Kategorie hinzugefügt:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -962,12 +946,9 @@ msgstr "%(comment_count)s Kommentare." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " -msgstr "" -"\n" -"%(comment_username)s schrieb am %(comment_submit_date)s
" +msgstr "\n%(comment_username)s schrieb am %(comment_submit_date)s
" #: templates/content/comments/default.html:28 msgid "No comments." @@ -984,47 +965,3 @@ msgstr "Senden" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Danke!" - -#~ msgid "(no caption)" -#~ msgstr "(Keine Legende)" - -#~ msgid "block" -#~ msgstr "Block" - -#~ msgid "left" -#~ msgstr "Links" - -#~ msgid "right" -#~ msgstr "Rechts" - -#~ msgid "Search" -#~ msgstr "Suche" - -#~ msgid "Symlinked page" -#~ msgstr "Verbundene Seite" - -#~ msgid "rich text (ckeditor)" -#~ msgstr "Text (ckeditor)" - -#~ msgid "rich texts (ckeditor)" -#~ msgstr "Texte (ckeditor)" - -#~ msgid "You may edit the copied page below." -#~ msgstr "Die kopierte Seite kann jetzt erneut bearbeitet werden." - -#~ msgid "" -#~ "You have replaced %s. You may continue editing the now-active page below." -#~ msgstr "" -#~ "Sie haben %s ersetzt und können nun die aktive Seite weiterbearbeiten." - -#~ msgid "Move to" -#~ msgstr "Verschieben nach" - -#~ msgid "Move" -#~ msgstr "Verschieben nach" - -#~ msgid "Replace page %(to_replace)s" -#~ msgstr "Seite %(to_replace)s ersetzen" - -#~ msgid "Create hidden copy of this page" -#~ msgstr "Versteckte Kopie dieser Seite erstellen" diff --git a/feincms/locale/en/LC_MESSAGES/django.mo b/feincms/locale/en/LC_MESSAGES/django.mo index df4e7c2c2d1649d458356cb3f65abd1699828c86..90b3c9b9e1f6a52c92c3222137bf0c22a24add59 100644 GIT binary patch delta 23 ecmeyx^owai7q79dp@FWEse+-Qm7&qZ>5l>5l\n" "Language-Team: LANGUAGE \n" @@ -17,16 +17,16 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "" @@ -34,7 +34,7 @@ msgstr "" msgid "All" msgstr "" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "" @@ -43,50 +43,50 @@ msgstr "" msgid "Category" msgstr "" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "" -#: admin/tree_editor.py:429 +#: admin/tree_editor.py:432 #, python-format msgid "Successfully deleted %s items." msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "" @@ -143,65 +143,45 @@ msgstr "" msgid "files" msgstr "" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "" @@ -228,15 +208,15 @@ msgid "" "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "" @@ -278,27 +258,27 @@ msgstr "" msgid "sections" msgstr "" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "" @@ -310,21 +290,21 @@ msgstr "" msgid "template contents" msgstr "" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" msgstr "" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "" @@ -361,12 +341,12 @@ msgid "tags" msgstr "" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "" @@ -383,27 +363,27 @@ msgstr "" msgid "modification date" msgstr "" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "" -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "" @@ -431,19 +411,19 @@ msgstr "" msgid "This will be prepended to the default description." msgstr "" -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "" @@ -458,63 +438,63 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "" @@ -522,7 +502,7 @@ msgstr "" msgid "parent" msgstr "" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "" @@ -586,23 +566,23 @@ msgstr "" msgid "Binary" msgstr "" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "" -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "" @@ -610,73 +590,78 @@ msgstr "" msgid "Other options" msgstr "" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "" @@ -692,26 +677,26 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "" -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "" @@ -752,10 +737,6 @@ msgstr "" msgid " By %(filter_title)s " msgstr "" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "" @@ -811,17 +792,21 @@ msgstr "" msgid "Insert new:" msgstr "" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." msgstr "" -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "" diff --git a/feincms/locale/es/LC_MESSAGES/django.mo b/feincms/locale/es/LC_MESSAGES/django.mo index 2096da47a7eeeb40d1d3bcff30ce08ccaff9a7a0..377a4c1550ad65a6fbaf6adf116120ebc07d73c7 100644 GIT binary patch delta 4686 zcmZA432;>P0mt$Ga>x;G2mu1|kpKzD<|G0^Caah+=1!%C(J}M$e3|38fV~K9Dtj! zAKrs>W%gos?7$-IbnWlqWyU1T$Ekw(9cFOCAF(ffi$k#QU}NUv80?KT*az1kb1|*h zAGhIfw73QzLtQ_ZKbrVBoPcGh35IYGtaVwVMX&lJ-<^qLbcnP(IL#e2q&7YAt4K?E`)Jj+3 zL2PjCX)JF#^%1BESE0_o8MQDUwV+1S0@mYHyb}|QX--hk1+Sw9_z-pCXQ&lkK&{|w zyaETX&(&Ct`n(f${v)pb4645qs0qF5+FwUa=q=PO{ct$@zl}mBH+~9sVv$b3d^97B z2}1!Eqs0mWp6m&Lk(~awL@Q_&i{w2f9veeHfbj^QJ;@TogYN))J)Vw=D2!g!WF78`K7_+ z%$>Eay}{L6P!qfzHNkDDj(4I4w$2XcF;u_LI!~c?XKC(+!7>Srrz>$fBCg@oy#pbk4x13!Tp z_yp>LSKa5Yp;q!PY6Ty;`lqPtK1X$Y!F}GHx0xo=7uBALT4*7v|1wO|^Izc_mL?l` z+o1+%KwS_+O>i^n)@(-&xEnRW2VMI?)Z_aIYN97l{k(|Dg`lo`4K=a1aj>5M-@6mO zMqT&~YT!$#nfD%(>Ua!l=2K7|&cJRs8+F}W)I=*#11~{s{c=1T;MURq! zvS`>#As0{LeEbA;PjkG~J)Vi0`4ZGX)u_iagsSg$?m_L)0o24FMosv69E)eM62C-E zv~(={uM_6*sV-QEyj4vNW@9UEzht5M&D zIPz*RTX8&gp!z@KK7TJkVH*wSQIAVKXRXBb*c0DJb@&_9N-v^T*p1m~1!*`B(=iX1 zqXyoBysb?;YO9Z7atAP%`U_Z&iSrcdDdf?58MZt3VK3^3P+Nb@wLgzNslS5i_$=z4 zzJvQPi&^NqaS99Z3)BQNCK|IAt8oUNMPB9X|D@E4rlKY=3w6)tqqexpeQw?72T(7X zBgms}o<@Bq-b8*5%$L{;1Cvwd^})W>(_P&|y||`ehQ^;qL0egk+A<%t)tg-VPUk+? zei*d_Cr}f8(ba#2TEJV*51i+)H|>8wP3+IE{x?ixeDfa)>Zs3@)Ct2;E6GAlWE$#A zvjEl6EvSLQsEMyd-J-br{4V$TF6SQ9iaT8WIaGfyVnP?bNx{S4B2SvRgc{fjraCS` z{cM(_I$DmJKr`yw-G@y80pPNByX4KaSer7f=g%JIMa)!jEZ?pQ2XuIjZA} z?!-QPqjcdA)VDhib>1}80CQ0*T7+8ADja~#sEH;}-+{YO=eMIKa4?_!S4YQa=z-6o zE;xyL>|R1m>|NLX5$gO;onN7LfIfU zxQzUSSaKJ+k?18>FBkCR(m9TMhF{;nYH zv`sDso8ACdWN1i58vV$BT z&yk%(KQj4bIEj;fWC5upH;_lk5TfH}q>JQ`ZDbf3N4`7sF1UyMK#dzoH=^fX$Cczq z>kEB)8@ z{P3G?O~(GNo+Ana_S%t8-al%k{e0AQ_RY)@w#VpE{UhOeZ<)U#ZkC4D`?hLyj@>!B z^YVC8vsYdliASP!W@&3pVWbogJ_>IahZ*nR9QTYxel`KxKVA-dt8tP#1~Ux7Or`n;Hw&_>pM1G4{QYSgh5L z^}T-avf#WHKcqf`^FwjJ%quP|DhU=928&C*qN1{*V%s)h%z#wAa7I~C>Eyyfdw9Y% zS1oN0MI*6#FV79u*4CCEZwW6ydJXX;B{jd$8Xk9B?Sm4JBCfc;z z>VB23rOfkV*3X?3m}z(AF0toxr`lj%o?Vx>z56(Ay@sZkN4GJr*7q7hF)!9y6Kp=ySr>_h zV)-_!a7XtRKWOI{O|YYjvjUziE3ULBi*p9)t~Gfrk#Li#XbrX0+My+-wxOgv5VFTh zT5WLZ$kZw3)y|3*MhkIspDJBs7hLg4Alfx?+O&Y(K7DmsC>-W?_`1jT7c;_LlgnxX e_JNsI_AfK9p{ueh#|A=OE3Zrhx;~pVD)3+ReM^!6 literal 16126 zcmbW73z#KEb;k=>6qYy0Q-MZUc31Y^eaUNB7WN4XyX?3#Km>H@dvDK7@7~*e>FztT zv&NuC1>=KYg5ry0Ra6o|5lM8T5*S}7245tRsEC@x=oj_VMAQ$H{Qgzd_x3(`nEQQa ze*LJft~zz<)Tz_+-6Ln+V)#9dyZ|}vxyCHr$Cw3&>Z&onKGK+L;cwv4@T#MXc|PpI zBjB6hY4A39Fr0z=!LPz|;Wwe`J@k19JOk?aA*k|KKt11thrt`+{_s|)dTxV@;d}k{ zZ^Gwr{;22U@L0}&1ZP7vQuhynG}#;pSHn3lgj?VN@F930d<5#fkHJIW&)_lecW?|o zj}z7N3dkk%7C0BaAM#4`5Ih||4%MFnXw2d8XoxD!>F^*}hk9-Z>irF-i2`9SePlh_5?^%a>?^3AuT?jLH5j+X*gzC??pvK{GsOR_RrmoM1 zqwq+$8jiyi@Wb$R@TYJAEKYWIy#v-c{|0QreFI~bz%jTKz5~vOUx8}R6Hw#+KTz$Q zbqZ~RN5Ez9rBMBU8K#6YeJ1{;yDG?u2(^g+nb@vzssM$&+~4m@w?C8f6!n58k9aCgKF;&{rS&5 z{~M|uzlEw-gCHINb^UOEehgImPJ(LRe5iVtK)v^D&lR4RLfbzmyxZCqnQ2P7=)cAZCs-M4t@*De}=H7D@lz%-1s=lRA z<8cn$4{m^}_a#v8zXt045u61xsQXh;{dx^lzi#yBH$gpj3sk+g`TO@kwPUBh{$;5C zeh;etA49eG34gxd9Cv;=RQ)f2Dt{`}`)hE2cn;J!Er)vVS~v@C^w&qB?C=`6Kimpc z-*r&swn07jN~rd|9!fuN_xJCB`*VI5)cZdU)vwP$)%y*o_J1F$zMsK;;eWyX;S*5p z{T;Y`e;7>nVI1H_uHQV@&8Np9Q`tNLHJ-=JbN;;sWha+I^|uLE!>y1hZaxY% z?q7v3f)tIT%V`$3v}mb;uMmE8sTRg3|YQATHGW3~GHjc!Be?E1}9? z1NHp%o^OR}$L;?7E_fm5_rrtXzBSkW!=U_!%!f=#b1qc5m%;bL zHar9#vB>dc_%hCGQ0;#sRQ)%@_3#651N$j$shz!K)#! zGOvYt|Hq;H_zaXDz6I6p??a8_lTdc>Tow)K<1mP6nq#2)u^g^}4LAWm1Xb>c7dsvY z_58_D{g?}nfHi;r0;vA4g{to-Q13kqBTzd}fO_r{sO!UU1YQlLhmSz%;YoNayyPrr z&p&{u#vFOJF{|JzxCPz-&xOB$G}SC1*ie72h3fx}Q0>1N%8qV@8t>cT`S9Q2i{Kn8 zVTm@wQ0ECe2)+ZVp4*}7xeFc+@AdaT4+%lc*P-nFr|>v<(2y&C8kD}yfU0jPRKG9q z=a)du>nq@~umd&TuY*U!o8Xb~c7Od7o)7rz4?*ekF{u9it3Uq*RC|Bz`M;je!N}F0 zL!jDqj6XjKs(o{z>RIaVUkKHoi=o;P!oy$zRnKdo>UlHN`)+}1|GS~=;sa3SKH=}* z@A*Zjem@LV{@?udpF`FE1l04-C0LPPIv&bzoCnp8mqXpZ4ju*n7^=RvLpx6Jc+T&I z($B+C?R>vb>_t)&E(~FGJ0PuS3=I z1E_j_0{4NNkV}y+@>j^dNQAVI3z6M_XH_nIfMd<^KS!8O{ohWG{t-F7f5jba_2=KN zTt_{2U#3fU`s?rZd^7wUk|2MC+>G>)hYE!*?QAAumKOLq3b> z*FZjLkMN(KB|gf*X5?Dr>&Vv-T%`T|J%4e__V?GG!ehukAk)b02vg7uBOgcp8F?e} zPsrO5{jNveWslridXYaC{=^^OUAcy7n3p48^4CJoSHL$Q-|^?TWD_HrH?KzCipbVJ zf*go^50S0uw*^^?q&ngEhltjbb%^H2dgO!1TaXiw0(k+VUlX~_9=SjN0`@~Dkwxy3 z`2)BHX(Oj00ixe5MDt0%OOPBnR44p2AMUY7gFn}Cco*_9WC;074CJNAhmpC6e8@(m{9REVz-`FG$OJMU zS%&EMXUGlq$o+YVKb{RA@yAo}ZOC?i{uTH|&kayxyOm3O|8-6B+l{{sw-^AAbuTj6CYkkMn#7d@XX6KhNOjkwcI#_-psUgZ%NA z;hD&Z$XAgIkUvGr-wqwj4)*e!Gq0I;I#E(=?&VRIgq>)99^_%%3eqGP+{}B8PF!qm zg$4JQHL_sg@;$0E!OCeK8H?LRlx;5JqOH2jpps_VOA0ReH|BLSrxj2<%7eJmO|v3u znK^kd5#~W7ijts{PDZVuNP{p)qN$*p=5Z0HN!`p#(x4f3bu!M>h;doScPbMh^GTJ^FWsNkCHak7oo6U*1 z-Li%4X(wvMp>H%TYod_xG@G{f)X2DqI`$-w+EJ4p1yA?HE;WpyHnXDLmh@XoL*s3thSJSd>xONshs>(5 zIYC{QZ(7e`(u~>y8VFjnxQJX2_Pn%!F=>Vv2?YYHzRYVgEP{3v=4dvF0;fr7p4TTJfhm1(tZf%aX$!hGwx`dkDrTM(U ztAEu*n2blkoZR>$RoCXOS(UciVV7nXS){XMEY473x@&j6ZFmJojJIte21kGMAnX-s zCoJM-*lte`2BaR0y7p#qix&6p3p(<_LDlIBsZ`N6ju1oNZg`CikS%+nL+hKTn%_grH>tPmkvpxzZqd<0y zjmXPzk`&o=kWZvNoCsqv9fYW#Qfe&oqI}5Oj(d_j_OV!QF|oCDGe(wr+8BAyx~&ay zGfVSytOztvZ8JC@PN$-5IE|B{a`DPEYnjV1%yFl2W>l2qvcJnvYUz)I4()41GF%4l zGQ68x8gSH{#7VbT*a3E4$85AtGqu*2n~n6wPXlxsX5&#IA5#xjMyN@8Ru#>5kC}q; z=M!`f&mko>qVYJk+ zd+nmmgK`jNIK}U+a%wWe8Ma^>lgkhqy`sRnoq5vxENaTPQGoVyApN`52)EhTLU*Y4 znX2G9>m{F|5=|DfX=EfAix|rCAUB&L>%p4NU6xMrg1{~5cHyzNP%uNLZZIIIvs^r_ zgItCeNt5yAbLPy;@pR2-bH)g!3Da!ZLVr(Qv%h{<9&nc7AE=bC|9_g+f2gu_T|h-n z&+ekU3QDUk>zizA-9)9dmI=4QOFwEfuzKF}$+$TYj52%72&yq7QJ6I+JeahYF+<6O z=)~Kddmph;KtD{d!A!T?o*v>M#RoR9kj-HA-b*k6Sq9W33@`Jo^ZKusk7?R;@R}^3 zc+bhWrP)*3yftNOAesW2Mbl{y??siEVY7!1q=C-!4W^CiPFiMU0w3S(6}gV4%!pQp zks|E|S|WIh8L^=t7`Q&?F)HqRurlb4xOG&lFljzB@mW5IQl9q7{^;T*v12M84aXUP zaacMZtBC&EjWSy?ldw=(jo~P!zBNAu_Sfh##9|n;nA-3;l~r*Nnl{sJ?9{1|U|}FE zXxi1?SrTvHI-v&cp)IRmI@mD_<$@>Y2;L)xDTSk^r$4PS=AKf%go4;cf`8Q$Kh!j@ZUhZS>TdW{ucNjE_$ZlX6j1 zJL@_CU zTT!|oi0e^(D3~aU?$E-8Q&UrQU$D*+xo|2hniCgHp1-}bWpUQszIxMDi(HS(LF#5v zm$@}C7{83Lob=;2->heRWNS1%#cFPSMEQ)3E}Z$%hjz+r^#eE&qXT@@v>BDr<>m_Y zhrcZQjG&GEuJopqvtsuri(MvCwg=XC5c#4YlzOcXQlr+jm`c>#+DNwrVFRC8H!sD> zw9;g5!8Bp{Q}HBHc%;y!8)cn1*OF%^HZxIcKV#-rK2z>b*uL2yb1Y6-E=&bi!?Q z=i|-516B^JBk>fM^U8G{7x=ru)N>d7#Nu|!7S$Vu)2Y${X3z_4v<#o|{6>2%J1v@q ziOE)-HAsP;jfS<&mXor7{DA5_=YowO*`>ybDRUbJS5f0S)nMnPJ^0!kTm)~&x_UwJ z^57!jb<5b>I%2AuEL5OxQy|sj+?1;#4v=FT{$vVs>>TMIQO+7&&iaY18PDA0?cTT{ z@=*M0^68F-j5pdo7qT>C|K?zvKjpT(Jm|M+_X{e^B(*D$`x_9P4~~3T+U|7{Q<;hc z)YVgJk$LvI#yWEM*ZO;Rm;<+-*~qpgB@Ab&I#XNMs$Jot^r2vF6ep`TjLhB?$vf3H z3O0}-nTTN_%O+;}~Z%!ycN8VA^72TeW1*r*c~Y5@B+1vaNbVyoMWD3qrd zh+UD?7nGqU7jf6BplmwJl1-eFFD1RBAyWOjKFVX&q^YlIZ%I=P{06_&F<;1>hMh)C ze`S2E$pv9ysPrk>Q>TTQ9T*<5BS^F@KW=7dx`KC_cyv_6Ze<1(z70s<0>Ze|WEtI9xYnzBK% z570xhM-!o0Q;snvzEDx+E|aUDXLTE^($veWtE-Y`P@N5S$fhyCD9+Alt|}ZLEYnt< z-Gptr&9q9LiR{X%rMy&a^_p#*HJO7h|B6je+Uwt?VKq=sIWOtEpOz>t-Oc>VtT{P~ zR%&y!Y!UWI(ykAgQcBU5-E6xosZG}6mj}685^p&!G?3dJ3n%%DuZwe;#$ad^?DeQm z@03Q+4(6lmdV*2MJcPwDZMdc3B!wHY>g|%j-Pk1aMoTZYN!&Oz!_GxgMcj27u!}QNHbM0 z7;mhN-mt+5wcp8RcDTsa_7H21iFq>iN2~3#)|x}CnT9oI?$o5f1MbjYrW^jK3%6Vshz z+-QKzXxyB+r)pEw?zKQpIHMEC(pQp0ILqS%bi+*$P6eT(%5=ZB0WF1n!`@^J2*tu(6#&Q!>;VctF5 zC`K=%pb%SNreonMRT7ys!mLRq@x|)dK-*@x*GAbqLW0|mAgTYXg}wG?jBN%9tsb_= zb-Pj$9F#-ewtH*Y?(b0<&lh+b>{{#Y-fOed+f8QYW0hnMNHVi!j9R%pdf+}5dcNGS z#_qYQ*nIQCw47sUm0a>uC!eWD8yPzlt50Cbe3#f; z_W9}C>(b-T(B8Uv;J#IEZL~p;j}Qj_vy38airNp_UKgJE_yD&u5hAfJk&hm?^VqtK zzT2z$(mBHThix`8h`S`SHl6I+fdZDoT%yq=Bped!VUYh5ReRG(51!83M0O)JZ+WMjXkS6=g5xSs#dkAO6~N%h#9;>p@1AK&1Igk{`!TkyHX!8C6%DZ5DH`y;6@M1b z+<^v^C1(4xo?CqW#KQ&cnLCq6o=JYeJJE9O2;23*Ek3T4e2FzNti%_k#p~r`;_;qB zF{;_iW`U;pCDE>qYFWk1D_fpW5d&eQ^L%PlHNx?`kxAu0wJG4g9>RKHBW#-B7WlFU zd5T?!OgRd(^6#Pz#=`EFG%hry|B8WA>9?TYFUC~!K%+Tr{kYa1HWay4wU*sd*Hjlz z5(Ph1aW$M>%N`Gm%BO3Ptd6N!!)Sd5ZLG{KpMxhlsu+%o^ofQD2K23!buUVo_b6V+ ztc7H#)nD?-qc#^GT%lCF3oxTC${>+*`8{&+BX%LMAD`uA`hg~mt)>FK>(gLG3MQ-% z(h{=QC-sd^D?j}vAFQaS*(SuY%EzZ+y_sLt8@(nwN;j@sv{GN!)81>;MFFJbZI8_r z=z>CSOMrXP0?by_2b6<}XZ2SJjrh+1yX8!RxjrA*O6S_$Wh>6R`kx%x4p!$<@Eq8z zyp8F++ax*c;s-u_kjP`(u^z**iTFzRUv5Kfs-EuyGxyl^{EETGx_kyD+kMBJTow7$ z%D`lwxgrxf&+k+Bsm%ov8oK;F!6eD~{;tkcLj*fZ_IA$)e}0v+jZvb|Iw!@d%us1d zyMLR`N2lbVZ9>NkJOKIk{-Vcw2f?vY-@Ue!Ds`(xOfGWe{mb_K{p)(IEE{?pdn)tVVlX#0=tbHN&=K4eqm{knFp??f=m%;`soBag9x)#;!R{%Tpx#)H; zd3m7xzuS0n;QmDfb@)EJ4Wl1Dqi+FhdG;7q61^QVZipRr0iMcsXcs*u~&BW8-t-NKR>v!OVSRRAq~q@ z?B(pnjn4)+a+YwLaoAkIZuM^J7Leoey1!wv+ z;Nw_(NF+>CWcDng{ir%rwDWYy^Q|(Si}B1fD1T7`O(8w%^i0fn6@U&lfl@=jBVP4BF>o8m}7cEp^Uzr, 2009. +# proycon , 2009 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2013-01-21 14:56+0200\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: LANGUAGE \n" -"Language: es\n" +"Language-Team: Spanish (http://www.transifex.com/projects/p/feincms/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "plantilla" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "orden" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "idioma" @@ -35,7 +35,7 @@ msgstr "idioma" msgid "All" msgstr "Todos" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Padre" @@ -44,50 +44,50 @@ msgstr "Padre" msgid "Category" msgstr "Categoría" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "título" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s ha sido movido a una nueva posición" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "No entiendo la orden de movimiento" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "acciones" -#: admin/tree_editor.py:429 +#: admin/tree_editor.py:432 #, python-format msgid "Successfully deleted %s items." -msgstr "%s elementos eliminados con éxito." +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "Eliminar los/as %(verbose_name_plural)s seleccionados" +msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "contenido de la aplicación" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "contenidos de la aplicación" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplicación" @@ -144,65 +144,45 @@ msgstr "archivo" msgid "files" msgstr "archivos" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "imagen" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" -msgstr "text alternativo" +msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" -msgstr "Descripción de la imagen" +msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "leyenda" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "imágenes" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "posición" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" -msgstr "formato" - -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(sin leyenda)" +msgstr "" -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "archivo de medios" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "archivos de medios" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "bloque" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "izquierda" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "derecha" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "tipo" @@ -227,19 +207,17 @@ msgstr "Ignorar los avisos de validación HTML" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"La validación del HTML produjo %(count)d avisos. Por favor revisa el " -"contenido actualizado de la parte inferior antes de continuar: %(messages)s" +msgstr "La validación del HTML produjo %(count)d avisos. Por favor revisa el contenido actualizado de la parte inferior antes de continuar: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "texto" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "textos ricos" @@ -247,9 +225,7 @@ msgstr "textos ricos" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"El feed RSS es actualizado varias veces por dia. Cambios en el título solo " -"aparecen en la página después de la actualización del feed RSS siguiente." +msgstr "El feed RSS es actualizado varias veces por dia. Cambios en el título solo aparecen en la página después de la actualización del feed RSS siguiente." #: content/rss/models.py:22 msgid "link" @@ -283,27 +259,27 @@ msgstr "sección" msgid "sections" msgstr "secciones" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "plano" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "título de la fila" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "título de fila y columna" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tabla" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tablas" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "datos" @@ -315,29 +291,27 @@ msgstr "plantilla de contenido" msgid "template contents" msgstr "plantilla de contenidos" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "enlace de vídeo" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Debe ser un enlace a un vídeo de YouTube o Vimeo. Por ejemplo: http://www." -"youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Debe ser un enlace a un vídeo de YouTube o Vimeo. Por ejemplo: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "vídeo" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "vídeos" #: contrib/tagging.py:117 msgid "Tagging" -msgstr "Etiquetado" +msgstr "" #: module/blog/models.py:28 msgid "published" @@ -352,7 +326,8 @@ msgid "published on" msgstr "publicado en" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." msgstr "Se establecerá automáticamente cuando se marque en 'publicado'." #: module/blog/models.py:39 @@ -368,12 +343,12 @@ msgid "tags" msgstr "etiquetas" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "traducción de" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Deja este campo vacío para las entradas en el idioma base." @@ -390,27 +365,27 @@ msgstr "fecha de creación" msgid "modification date" msgstr "fecha de modificación" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "tipos de contenido" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "fecha de publicación" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "publicar hasta" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Si se deja en blanco la entrada permanecerá activa para siempre." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "visible de - hasta" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Publicación según la fecha" @@ -438,25 +413,25 @@ msgstr "meta descripción" msgid "This will be prepended to the default description." msgstr "Será incluido antes de la meta descripción por defecto." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Optimización para motores de búsqueda" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Editar traducción" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Crear traducción" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "traducciones" #: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" -msgstr "Esto crearía un bucle en la jerarquía" +msgstr "" #: module/medialibrary/forms.py:64 #, python-format @@ -464,78 +439,72 @@ msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -"No se puede sobreescribir con un tipo de archivo diferente (intento " -"de sobreescribir un %(old_ext)s con un %(new_ext)s)" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" -"Se añadió con éxito %(count)d archivo de medios a la categoría " -"%(category)s." msgstr[1] "" -"Se añadieron con éxito %(count)d archivos de medios a la categoría " -"%(category)s." -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" -msgstr "Añadir los archivos de medios seleccionados a la categoría" +msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" -msgstr "Archivo ZIP exportado como %s" +msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" -msgstr "La exportación del archivo ZIP falló: %s" +msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" -msgstr "Exportar los archivos de medios selccionados como un archivo ZIP" +msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" -msgstr "Previsualización" +msgstr "Pre-visualización" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "tamaño de archivo" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "creado en" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "tipo de archivo" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "información del archivo" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" -msgstr "importados %d archivos" +msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" -msgstr "La importación del archivo ZIP falló: %s" +msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" -msgstr "No se indicó un archivo de entrada" +msgstr "" #: module/medialibrary/models.py:43 msgid "parent" msgstr "padre" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -581,7 +550,7 @@ msgstr "Texto rico" #: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "Archivo ZIP" +msgstr "" #: module/medialibrary/models.py:210 msgid "Microsoft Word" @@ -599,101 +568,102 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binario" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "descripción" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" -msgstr "traducción del archivo de medios" +msgstr "traducción del archivo de media" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" -msgstr "traducciones del archivo de medios" +msgstr "traducciones del archivo de media" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Esta URL ya está en uso en una página activa" -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." -msgstr "Esta URL ya está en uso por otra página activa" +msgstr "Esta URL ya está en uno por otra página activa" #: module/page/modeladmins.py:41 msgid "Other options" -msgstr "Otras opciones" +msgstr "otras opciones" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "en la navegación" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Añade una página hija" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Ver en sitio" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -"El contenido de la traducción original se ha copiado en la página " -"recién creada." -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" -msgstr "No dispone de los permisos necesarios para editar este objeto" +msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "heredado" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "extensiones" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "activo" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "activo" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "URL efectivo" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"URL efectivo. Debe contener una '/' al principio y al final al cuando se trata " -"de un URL local. Este campo afecta a la navegación y a los URLs de las sub-páginas." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "URL efectivo. Debe contener una '/' cuando se trata de un URL local. Este campo afecta la navegación y los URLs de las sub-páginas." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "redirección a" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL de destino para redirecciones automáticas." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" -msgstr "URL en caché" +msgstr "URL en cache" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "página" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "páginas" @@ -709,34 +679,32 @@ msgstr "Añade una breve descripción resumiendo el contenido de la página." msgid "Excerpt" msgstr "Extracto" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "extensión de navegación" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Seleccione el módulo que provee sub-páginas para esta pagina si necesitas " -"personalizar la navegación." +msgstr "Selecciona el módulo que provee sub-páginas para esta pagina si necesitas personalizar la navegación." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "Extensión de navegación" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." -msgstr "Seleccione las páginas que se mostrarán como contenido relacionado." +msgstr "Selecciona las páginas que se mostrarán como contenido relacionado." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Páginas relacionadas" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "Sitio" +msgstr "" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" @@ -752,8 +720,7 @@ msgstr "título del contenido" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" -"La primera línea es el título principal. Otras líneas serán subtítulos." +msgstr "La primera línea es el título principal. Otras líneas serán subtítulos." #: module/page/extensions/titles.py:15 msgid "page title" @@ -761,9 +728,7 @@ msgstr "título de la página" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Título de la página para la ventana del navegador. Si se omite utilizará el " -"mismo título." +msgstr "Título de la página para la ventana del navegador. Si se omite utilizará el mismo título." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -772,11 +737,7 @@ msgstr "Títulos" #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " -msgstr " Por %(filter_title)s" - -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Buscar" +msgstr "Por %(filter_title)s" #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" @@ -796,8 +757,7 @@ msgstr "Imposible de eliminar el elemento" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Imposible eliminar el elemento, porque es padre de al menos otro elemento ." +msgstr "Imposible de eliminar el elemento, porque es padre de al menos un elemento ." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -805,17 +765,15 @@ msgstr "Cambiar la plantilla" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template?
All changes are saved." -msgstr "¿Deseas cambiar la plantilla?
Todos los cambios se guardarán." +msgstr "¿Deas cambiar la plantilla?
Todos los cambios se guardarán." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"¿Deseas cambiar la plantilla?
Todos los cambios se guardarán y el " -"contenido desde %%(source_regions)s se moverá a " -"%%(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -837,30 +795,32 @@ msgstr "Antes" msgid "Insert new:" msgstr "Insertar nuevo:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Región vacía" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"El contenido del sitio padre se hereda automáticamente. Para sobreescribir " -"este comportamiento añade algún contenido." +msgstr "El contenido del sitio padre se hereda automáticamente. Para sobreescribir este comportamiento añade algún contenido." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Añadir nuevo elemento" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "Añadir otro/a %(verbose_name)s" +msgstr "" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" -msgstr "Eliminar" +msgstr "" #: templates/admin/feincms/fe_editor.html:40 msgid "Save" @@ -900,24 +860,24 @@ msgstr "Página inicial" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "Recuperar los/as %(verbose_name)s eliminados/as" +msgstr "" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "Pulse el botón de guardar inferior para recuperar esta versión del objeto." +msgstr "" #: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "Historia" +msgstr "" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "Revertir %(verbose_name)s" +msgstr "" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "Pulse el botón de guardar inferior para revertir a esta versión del objeto." +msgstr "" #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -941,36 +901,36 @@ msgstr "Editar en el sitio" #: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "Añadir" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "Añadir archivos de medios a la categoría" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "Seleccionar categoría que aplicar:" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "Los siguientes archivos de medios se añadirán a la categoría seleccionada:" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "Añadir a la categoría" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "Cancelar" +msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" -msgstr "Subir varias archivos de medios en un archivo ZIP:" +msgstr "Sube un archivo ZIP:" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "Sobreescribir" +msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" @@ -985,13 +945,9 @@ msgstr "%(comment_count)s comentarios." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s dijo el %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s dijo el %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -1008,6 +964,3 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "¡Gracias!" - -#~ msgid "Symlinked page" -#~ msgstr "Página enlazada" diff --git a/feincms/locale/fr/LC_MESSAGES/django.mo b/feincms/locale/fr/LC_MESSAGES/django.mo index c69de84f283b91fdae963fc935acb7774e38c6f1..c728d82d9420fefc7369f772b9103294a21d3411 100644 GIT binary patch delta 3396 zcmYk;d2EzL7{~D`MJTu+w9pn>@Z~HOdTcpc6h&?+mwQh!KqOiZ=L%Mu`Svh!-mA_qRI`-}HGuGxNSX^US>Oyy<)M zl5-O0v%Bvx9J`4^qOQ9!C-6WPCyrOIH)bI2$G&(1eRvi#@hkM>*VqI5bFnw(V>XV! znK%i1;TF6B+pv!@3A2YnE)5+R#AB!*4&!P+oPhLgW}yaHg4f|nBv-S})&n@0dI%@r zPUO!V<@6$+M!GgZW-$e$*n{!S0SY~7NTMcv9F=J&s-v@*gPEkQ4)Ra~kHpnjjJm%K zmEcqM`g5p$_n}sx1KaQdj>9ms^E1BLN1+ry!~p({6 z9EnY4u>QJn91R-4Z=GsyoMoMlsb`N$bS3KkAZjKp zsEKSw^|uQ(z+=|uP%H5==HU@k!XM?Z{;am?qCp*BL{``Qh3cpe>!_v7=A^g12sPkX z)PNIE_f1C)I2$$NC8&f~*!nuu@9L00)5J;R?nu}M4>hA#Q60a9%J77(e_-ohpgR5* zb^nj3fqz9UvG%G4%0ea9AJv|VN^B^m-Whv6F_waUP;MJ4Q8!LQ4KNew+bl#jf(f7! zjGzWcU^m=}`rX5*gq}bRv=_CaFJWhfF^7;pvytb(A}7q_6tooWs16U|Bs`4z;YBRM ze{mER&T8WM^XK}k0bC)Y{7p}{WK3szXRJ*--*4L+W$!k%KR8=h9_

J_N@yeMS?xe=pS{RaFmIq{bQ)9J2$gUb>i+Lh_g_KvJHSZ~SZFOl zy<5{9p1%g1OM{-#LR7~!sE$L{II5%VsO!6}&!F1(p%Un@^@FIDI*fWZ-bVfIL)3Vm zp{{p1iF9V)(4ZTBu@|nOo^5v?RB9WcI?6>QIvTmfOu^x}3i)R%8q@&0 zP%HB!Dxv35yXF}sF_DmnQcNP(uUejkE1%?hk6tpn1MRnG}q3xwloj# zBD5Ry;@(e;C3X`J6Ehg!u&vEagl4JC^caeWV&Z0^nb2`t>YPqCK)IS==cYa~_u6aA zaTk$k>#K2!EpNd4h|$EYwrvIDr}n(9n@tqf*h(CkWa`j;dckz)1*#*Ws&E9;q&_Mt zjT#&}08vVGQ-z}}P3pXZ zbNGMtM{Ic~>V?#!o~Y-qLvLgwF^$+ltR?tJnHr*%*iPsuBxVtOc~k#VZ9^TC32ieS z6NvT10%8<#Cs9c_gpTV7y;po3&1{W7oI(W=A?k_w#5iI)q2nH65wV%Lo0vq*A@nw{ zB6K{M#+2g{Vk;4|ZOc$Q<91@9ZMy}vy-W0hRoTXn^(sBD7I394Z^Wgx{E)Z6H@IMW zU7ZtX2sPF@Ew%NoQ8nzgI-!``EY?z0R#qR1HN@AK2AZ47f^H}rXo_Al6phB+Xz#^~mX*wixV5oR zbGT$?ZOpB5D$4!iOZ?>}6%!r5zsg_X`SJ>US6j*}tNh;hyz1$*BW^g*;Eb^&wYIjF z#v--hXej7zN)6Z&X};GD#G+*_*T!tD4cEt+Q&})lR_wLst@c&hmMSM0@&3#!&Y#-b zEUt|>qs9b7jWIWJPb?H`bc>^oSDioF+nj%M@_7EDOy7ccUu$xm4RP0LbiLfdGu{t{ z+mlZYiFWg{oKwlO&K()a8;3ug(Jv5*n?Q3o=7!@@hl+P<#OT3MvSPNz8a1(Z_cu1j M>zm_V=E!&c13+wa{r~^~ delta 3641 zcmZwJ4Qy3s9mnyf^tNoJ3|d$VE3St^%Pp*>EtGYPw+>3d7AP+T6p>wSPj4?R_m*?d zWvj4V7iy!tDMJ|{W)a^E7;_1i-OdlCqtKW;aWnGIMEJP_ecL{U zd9;Ty7r%)0cpCHZiuD~VpnVOC@ejDhn3VZD6^*rgvN2Pz75Qg&@Kb^=cH?2xjbk_! zKgLNok=baVX{d?Zg{;9iwq1#L(O!UyaV>JIIfO4UzIl=gb1*?hZ^A}YhcTRpNxTgo zK~3~=R7b-&4KJbY|21mhKcepc3+}?dqVC(staW@R&cQtxV0?3oiUt}&QeuX25PymH z;I5)s|V$c7|9)BN|sT)NCb|W6{e!55?3+&hwUPt})Zr29 zAZnl!)>Ej=yo{yzUDU*{B2UTu1~tG9rgdCsNGS88hAcx+(juWx^NY0 zz!uaBI#4s;Zri(2H-=Fi_MrwoYTF~ImA#7U_#A427i{~oZNG==cMNrX>N*t-d=oYB zEmX?$Sgr<~jGABx>UbIIx;dzhs_pqY)b)+Fy#jUJYScjMQ4`;aY&g?{Of+R4qM`wg z;{<#Xb>q{hiH)EJI)h5>S231j%y*Evn#vj3Sc!kb-B>m=`%DLrEo`1Zb^HQq|DMHuyn>q8a=tRm$!tP>aJu=?1dgHx z973)9q-~$UdD{P9p>jX|)Lt;L%$V=dE97{}Jk4co+33KEVBW9aBp2&QE1K3S$NBUet_Fq6T~(JMl$4gCF5SeD?0_m+&oI zMEfRs7%b0zs9r>+{4%Pa94DK>+pxnJGt(jeTERXJXh07&(}z*d_Bbk~r%~JP9O_yA z1hwLyqpp7swU9B?eIKIk3y_A)ON)ARbF7O|nP{0!{x$F>4(J(nqB@SCI_|d~Ms+k~ z&ktL_WRJgsn!q<~`#fsJ-$%VWKScHWE^55r+4Ey5Dw^4Kd%-{Li2%<*&u$W`qZz1` zm!mqIi<EMwKk$wwhT3)7F6nYU?s*-{XdV&(3epQdlh+!Q|5Jh;38@Qzd#Li z4K>gQ)<2;-`VckX$EXS3LR}x2n>}BEI$w7U4)tae;*ZIP}7F`hWDaU zHh=*fM9ugFYCj!-#3oFuf5 zcM~cuv4UtO`iN(V?S!(TRI9AZVj_6N)`hmM3h%X9O)Mq$5&B+?==rO}h%K2~Hub9R zv2C(y9wC+yM~OP3o7hYIZ_!uMA>#JLHf*%@6WBvMPCQ5)B&sz2PAZ=vRP_972z^A@ z0Or%g0zzdyaZjd}{n-!NLJttyTIIy&3BJ;q&-tVHG_i(gAqI%Yh)!adc!IbiyMF%a z(FhSLgG7?(CAJa^iF#rO(MI$WDr*V7fX@+!h^d6O?thnB8hn*A=&0CR85IlG)qpY!1PnhfL|>_c)QKmh-@XQyJ`z z_W7>2$B+7bZgs*jg~3?d35WXqXgpS(zA)+TKsV>p*CsXPx!rNk9i3WOmKz9p;huDG zO1vWEMO@$M+|urF(g`K~`2LU|4LhFO74_V(pQs%@HKk!f{xvF5pPnA~XH}`uN&nD8Zl`hX~ zJ{XGmqc=)BatqgYxiLR_AnCH`^t!Ukw{LO7JuYc+(?zo$t58Pz<4Nz6M6jB~C;8#F z#OTN@Ka&@ayyTVtAfUXAzFppylOJIoJ!E?Jb2-I(y`*o#@tE(%k_ktx^tp\n" -"Language-Team: LANGUAGE \n" -"Language: fr\n" +"Language-Team: French (http://www.transifex.com/projects/p/feincms/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "modèle" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "séquence" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "langue" @@ -34,7 +34,7 @@ msgstr "langue" msgid "All" msgstr "Tous" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Parent" @@ -43,50 +43,50 @@ msgstr "Parent" msgid "Category" msgstr "" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Changement %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "titre" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "actions" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Vraiment supprimer cet élément?" +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "contenu d'application" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "contenus d'application" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "application" @@ -143,75 +143,55 @@ msgstr "fichier" msgid "files" msgstr "fichiers" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "image" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "légende" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "images" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "position" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(aucune légende)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "fichier de média" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "fichiers de média" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "bloc" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "gauche" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "droite" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "type" #: content/raw/models.py:18 msgid "raw content" -msgstr "contenu brut" +msgstr "contenu cru" #: content/raw/models.py:19 msgid "raw contents" -msgstr "contenus bruts" +msgstr "contenus crus" #: content/richtext/models.py:22 msgid "HTML Tidy" @@ -228,15 +208,15 @@ msgid "" "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "texte" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "texte" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "textes" @@ -244,10 +224,7 @@ msgstr "textes" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"Le champ rss est mis à jour plusieurs fois par jour. Un changement dans le " -"titre ne sera visible que sur la page d'accueil après la mise à jour " -"prochaine." +msgstr "Le champ rss est mis à jour plusieurs fois par jour. Un changement dans le titre ne sera visible que sur la page d'accueil après la mise à jour prochaine." #: content/rss/models.py:22 msgid "link" @@ -281,27 +258,27 @@ msgstr "section" msgid "sections" msgstr "sections" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "plaine" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "titre de la ligne" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "ligne de titre et de la colonne" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tableau" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tableaux" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "données" @@ -313,23 +290,21 @@ msgstr "" msgid "template contents" msgstr "" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "lien du vidéo" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Cela devrait être un lien vers une vidéo YouTube ou Vimeo, à savoir: http://" -"www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Cela devrait être un lien vers une vidéo YouTube ou Vimeo, à savoir: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "vidéo" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "vidéos" @@ -350,9 +325,9 @@ msgid "published on" msgstr "publié le" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Sera mis automatiquement une fois que vous cochez la case «publié» ci-dessus." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Sera mis automatiquement une fois que vous cochez la case «publié» ci-dessus." #: module/blog/models.py:39 msgid "entry" @@ -367,12 +342,12 @@ msgid "tags" msgstr "mots-clé" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "traduction de" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "" @@ -389,27 +364,27 @@ msgstr "date de création" msgid "modification date" msgstr "date de modification" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "types de contenu" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "date de la publication" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "date de termination de la publication" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Laissez vide si l'entrée doit rester active pour toujours." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "visible de - à" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "" @@ -437,19 +412,19 @@ msgstr "description meta" msgid "This will be prepended to the default description." msgstr "Ce sera ajouté à la description par défaut." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Modifier la traduction" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Créer traduction" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "traductions" @@ -464,63 +439,63 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Prévisualiser" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "taille" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "crée" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "type de fichier" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "" @@ -528,9 +503,9 @@ msgstr "" msgid "parent" msgstr "parent" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" -msgstr "slug" +msgstr "télougou" #: module/medialibrary/models.py:49 msgid "category" @@ -592,23 +567,23 @@ msgstr "" msgid "Binary" msgstr "Données binaires" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "description" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "traductions du fichier de média" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "traductions des fichiers de média" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Cette URL est déjà prise par une page active." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Cette URL est déjà pris par une autre page active." @@ -616,76 +591,78 @@ msgstr "Cette URL est déjà pris par une autre page active." msgid "Other options" msgstr "Autres options" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "à la navigation" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Ajouter page enfant" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Voir sur le site" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "hérité" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "extensions" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "actif" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "adresse URL forcée" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Outrepasser l'URL cible. N'oubliez pas d'inclure des barres obliques au " -"début et à la fin s'il s'agit d'une URL locale. Cela affecte la navigation " -"et les adresses URL des sous-pages." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Outrepasser l'URL cible. N'oubliez pas d'inclure des barres obliques au début et à la fin s'il s'agit d'une URL locale. Cela affecte la navigation et les adresses URL des sous-pages." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "rediriger à" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL pour redirections automatiques" +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "adresse URL temporairement enregistrée" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "page" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "pages" @@ -701,28 +678,26 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "additif de la navigation" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Sélectionnez le module fournissant pages pour cette page si vous avez besoin " -"de personnaliser la navigation." +msgstr "Sélectionnez le module fournissant pages pour cette page si vous avez besoin de personnaliser la navigation." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "" @@ -744,9 +719,7 @@ msgstr "titre du contenu" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" -"La première ligne est le titre principal, les lignes suivantes sont des sous-" -"titres." +msgstr "La première ligne est le titre principal, les lignes suivantes sont des sous-titres." #: module/page/extensions/titles.py:15 msgid "page title" @@ -754,22 +727,17 @@ msgstr "titre de la page" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Titre de la page pour fenêtre de navigateur. Identique au titre par défaut." +msgstr "Titre de la page pour fenêtre de navigateur. Même que le titre par défaut." #: module/page/extensions/titles.py:43 msgid "Titles" -msgstr "Titres" +msgstr "" #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " msgstr "Par %(filter_title)s " -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Recherche" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Vraiment supprimer cet élément?" @@ -788,9 +756,7 @@ msgstr "Impossible de supprimer cet élément" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Impossible de supprimer l'élément, parce qu'il est le parent d'au moins un " -"autre élément." +msgstr "Impossible de supprimer l'élément, parce qu'il est le parent d'au moins un autre élément." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -798,19 +764,15 @@ msgstr "Changer modèle" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template?
All changes are saved." -msgstr "" -"Réellement changer de modèle?
Toutes les modifications sont " -"enregistrées." +msgstr "Réellement changer de modèle?
Toutes les modifications sont enregistrées." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Réellement changer de modèle?
Toutes les modifications sont " -"enregistrées et le contenu de %(source_regions)s est " -"déplacé vers %(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -822,29 +784,31 @@ msgstr "" #: templates/admin/feincms/_messages_js.html:14 msgid "After" -msgstr "Après" +msgstr "" #: templates/admin/feincms/_messages_js.html:15 msgid "Before" -msgstr "Avant" +msgstr "" #: templates/admin/feincms/_messages_js.html:16 msgid "Insert new:" msgstr "" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Région vide" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"Contenu du site parent est automatiquement hérité. Pour contourner ce " -"comportement, ajoutez un peu de contenu." +msgstr "Contenu du site parent est automatiquement hérité. Pour contourner ce comportement, ajoutez un peu de contenu." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Ajouter un autre" @@ -980,8 +944,7 @@ msgstr "" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " msgstr "" diff --git a/feincms/locale/hr/LC_MESSAGES/django.mo b/feincms/locale/hr/LC_MESSAGES/django.mo index ad91b28dc832135082e1e4518189edfc7725187e..8f944905c3660d710aa1539ae72dd5573de106a7 100644 GIT binary patch delta 4273 zcmZA43vg7`0mkvO3Gzq+2>}u?2BHZNNH)7kh`>@oBmtpVBvepAN(f7`lXP05?A=i^`?+m=*gmf=<$h96=Unlxkb;5wX)({T{4 z#}s@Rxs}oxP(dgHKt?IU}MTL8~fvO9DsF5UrZ|w z#CFWUD6YhVsOtywqmJj{7!05~ScPe{ZyG7|qryQAdNZn_DAGf-2Q`v?sD=+<1Y_6- z^M|;4F_--k)cFfh_gjM3Vl7U18Hu%rDO_!)r{Q9YiI8tGE( z#Cltw%q)bQ|)1z)L=iHg+oydEkT{P0`(~BPy=p5CeLge!Ti%1vzH28a2&Px zUO`RSDeJqa2F{{p=mXUGpV|Gdtpk}R%|sUJ_-NGmUeruYL3QM2yFb^lh4~m?G#Kx> zb%m|3xBD%q4z5FWupM>d?Wl&M)(-1)sQbQXJ&u}@lc0?Ij}C2^ ze^AK7^c-F_oQN!FQ-k`%K7eZAG31$<-FOQ=g{nViy?~mb50P7%Pf%+l{d)Ir#yFhE zeg&$dyRK*cwP^NI!PnFrLhZkT>cCsL8ZV-zY|#zw4Qug6_8rvwd<-@9r%+RT2DSM9 zf||*XQ8V&6s>7aKx4vJlW6WAA22-IEwxOnWC-R@!&5tfPfokAYWPO>_I0rAIK3Ef( zKFw4J^~lzu&fkuDJ33G^(rxR1k9ss0916!M{1f$T505tH4tyCkMQLN)6SGiL>qU*I z40U`OR^S}uV`z4uX6gW{ftRhn#lGyHL*8U_5zEmrV~trwp#n8^M^O#^4As!9s40HS z)}Kes$R*SbKffc$4p^22e*T%w>G<#Lv8JRW&W z#*eq+0@U$6*bnz%5Zm`9(DdFn1uhf_9<`&l!}^}5pj9`1r+*IaT99l zW}+6)BGfYsq8g5%p7DLC1|Gpa7)5pb32UeI8B_-jqOR|@oUv5*4>hN0BKsKPGsn||Ii()To zb)P`h{{hvp4^TI_ikg`LUiUkYiCW!Rs2i7J3Qj_exB@kUx1l<|1l4fR?zeh*{_5!l zDw1)lJ+KS){&%8|_n>b4OVo^kUPoa zWHsp_8ueJRfy~tVuW8YCE4epb`rjYDAwRZNZK#DhpETLJRBJ8XXUiSfZOd9$+MXc3 zc**^FFplnSw+8$!`2mTN?~{dOIw>LAs)?Rw3(jRDn(F;8{|v9lOo8-hyk$Q>2uPAOVg@gbtLR-{-)*ns>Yhus+yp$w#7FtnlWl|%3NC$$f<3KHjipan3A+Jtspum lXJ_n4&XK;cy0HnK*wgvRiLn<7wt8aIydQgFWxfHP{{oskyjuVO delta 4462 zcmYk;3vg7`0mkvOd5{n`2`>S|BbR`XU=p$sVn9GhLIX5HK+=LiWD}NULz0EfCO|~i zf)dc;BSBPrfE1)q9?B{yl}4G?+Kz2!Y-ea^m;$Yil{yx&YCGtR{eQU!w>u@-3z_GXsy?7d@;BPPk z%>cJO6O*Zqz(mYJAC7a|V`d2j`ZUX}0US!b5!3J?9Egu&1@6aG{3rIsPcaj(VLGO9 z@DLn^t8gOf{N4O$0*7%NzKLEFGv-4I4BGq$Q!r_eF`B#=)zL8207s){l8frN5TjU% zNqEe9630;QMjd}1b-ll17Jh=0Fm8TKSB$DpLtS?k>iqer6{;D^`s;v=G-!mIu>!Z@!}u=d z4O)Tm z$ZDE9kja>8)P;hm6Pr*EWh-haAGGd3b<~MkxxJ|4kJVUv%# z;0)BQC`WxbmY^=Y3^jltY5;3d$3I~AZ$V9HCu$;Hw!Q~--agcI5BKip{`XMO`~SAx zaSk=(k5L_bff{kbNVlGWz0VA)gYl^23sD0sMGc@Fb*tv0I$nqx=smXmKFrYjAEclY z+E5qVggS65>cs7+0X~UZq5XFMYpC;1qXzIMYG%JfeLpUsCh!UBde<-kzd@asFpBlp zh*K%3<3Xqnvap-K0r{xc?1OCg(>cd+|3)mwv9#Zhx^??-A|6NHFmnO*LHi%7qtwyv zEzH0&>H|^jHKV!zD%8@TrScV`A=7&Ej*UrLIQJXenw*gQ%5RhZ^Vx+rAk$Qr~X(C$Jn^ z;=V|e$v_=njJg%2sEJhKJgi3_9*qM>W0n~(!+Wn_+Hucz93VcOP%6NCF9Mp+EYdQ9zUV|FIGUVH2 z)?fv0!v=g8wSpzNZijcGI;=!3^+MYoK+U`fllA`ZrJxQD;tV{BTk&I@gyB5CVt4>2 z;3W)UKPnVWD{B8<)OF4y7dHPuZnOCa=U~5E-TjL(g?cTf(Z8vupb<8sZowARL-jN! z;Stn@Phc9JvYy4h)PIj!v2)gsFqQf>)WesU?>EBGDpbqAuI;=*` zpvGEj^`iz5L|q_aZAW#u#qNI;HL%^beIM%SKa85#Tj<3#qxS(~ypTz(hQc z`eShsb>aV_2J|&*=6ws@r5u2ofP?Bd&(^1)R;mp9;a#?UDeC)BXZLR^Wc_vF4jQyH zyX=lbm`?p9YU$oW4d^eZj;^3O{suME)QRr1lZ9HLiKu~2woXS)WHxHW<{@8UvoK~4 z2wT@%)vg(IpdQXn)Wi8Qs)IMIXEB5NJE#GkL(TZ#s3pFJTG6B;cL1rV^V3lij18io z6&Q_~Sco3nN%;Jm17sD^rVg|<5q(A{lkbr_awl z_m6EUIoextKdZ+mcN5*?d1O4{bvB2HzFyhn38IY^HV=`hTwq%}ZeiDI%+h-t9qTH_Pj|2lz zr)E)=vnm{M{H@V&lRp}&cOrq6p-7-U+EN(*?T{-8$#sq4`Ze)WH&=QR1FNF(ud;S} zk|Uwu>S(-U#1PNewCV+m3(6w_&J8ygRQRKTsZMc`uehM7w7^&5_)4exZtuE0a=4e4 zk^JylaaaFQRimqB&9AJPRXN+4R#i2#F;p0i1ZSjG`J02S{va1w9qHOTs~CodxB2tpCC-UH8P$3^FQ|_ PuMD&_hvN-}X`cTBzmUy~ diff --git a/feincms/locale/hr/LC_MESSAGES/django.po b/feincms/locale/hr/LC_MESSAGES/django.po index 6bc94e8f5..0a562024c 100644 --- a/feincms/locale/hr/LC_MESSAGES/django.po +++ b/feincms/locale/hr/LC_MESSAGES/django.po @@ -1,34 +1,33 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: -# Bojan Mihelac , 2010. +# Bojan Mihelač , 2010 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: LANGUAGE \n" -"Language: hr\n" +"Language-Team: Croatian (http://www.transifex.com/projects/p/feincms/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" +"Language: hr\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "predložak" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "poredak" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "jezik" @@ -36,7 +35,7 @@ msgstr "jezik" msgid "All" msgstr "Svi" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Nadređeni" @@ -45,50 +44,50 @@ msgstr "Nadređeni" msgid "Category" msgstr "Kategorija" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Promjeni %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "naziv" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s je premještena na novu poziciju." -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "Uputa za premještanje nije uspješno interpretirana. " -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "akcije" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Stvarno izbrisati zapis?" +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "sadržaj aplikacije" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "sadržaji aplikacije" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplikacija" @@ -145,65 +144,45 @@ msgstr "datoteka" msgid "files" msgstr "datoteke" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "slika" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "naslov" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "slike" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "pozicija" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(bez naslova)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "medijska datoteka" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "medijske datoteke" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "blok" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "lijevo" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "desno" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "tip" @@ -228,19 +207,17 @@ msgstr "Zanemariti upozorenja HTML provjere" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"HTML provjera je pokazala %(count)d upozorenja. Molimo pregledajte ažurirani " -"sadržaj ispod prije nastavka: %(messages)s" +msgstr "HTML provjera je pokazala %(count)d upozorenja. Molimo pregledajte ažurirani sadržaj ispod prije nastavka: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "tekst" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "formatirani tekst" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "formatirani tekstovi" @@ -248,9 +225,7 @@ msgstr "formatirani tekstovi" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"RSS polje se ažurira nekoliko puta dnevno. Promjena u naslovu će biti " -"vidljiva na naslovnici nakon sljedećeg ažuriranja kanala." +msgstr "RSS polje se ažurira nekoliko puta dnevno. Promjena u naslovu će biti vidljiva na naslovnici nakon sljedećeg ažuriranja kanala." #: content/rss/models.py:22 msgid "link" @@ -284,27 +259,27 @@ msgstr "sekcija" msgid "sections" msgstr "sekcije" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "jednostavno" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "naslovni redak" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "naslovni redak i kolona" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tablica" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tablice" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "podaci" @@ -316,23 +291,21 @@ msgstr "sadržaj predloška" msgid "template contents" msgstr "sadržaji predloška" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "link na video" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Polje treba sadržavati link na youtube ili vimeo video, i.e.: http://www." -"youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Polje treba sadržavati link na youtube ili vimeo video, i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "video zapisi" @@ -353,7 +326,8 @@ msgid "published on" msgstr "objavljeno na" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." msgstr "Biti će automatski postavljeno kada označite `objavljeno` polje iznad." #: module/blog/models.py:39 @@ -369,12 +343,12 @@ msgid "tags" msgstr "etikete" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "prijevod od" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Ostavite ovo prazno za zapise u primarnom jeziku." @@ -391,28 +365,27 @@ msgstr "datum kreiranja" msgid "modification date" msgstr "datum izmjene" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "tip sadržaja" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "datum objave" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "datum kraja objave" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." -msgstr "" -"Ostavite praznim ukoliko članak treba biti aktivan neograničeno vrijeme." +msgstr "Ostavite praznim ukoliko članak treba biti aktivan neograničeno vrijeme." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "vidljiv od - do" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Objava vezana na datum" @@ -440,19 +413,19 @@ msgstr "meta opis" msgid "This will be prepended to the default description." msgstr "Ovo će biti dodano predefiniranom opisu." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Optimizacija za tražilice" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Uredi prijevod" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Kreiraj prijevod" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "prijevodi" @@ -467,7 +440,7 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." @@ -475,56 +448,56 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Pregled" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "veličina datoteke" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "kreiran" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "tip datoteke" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "informacije o datoteci" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "" @@ -532,7 +505,7 @@ msgstr "" msgid "parent" msgstr "nadređeni" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -596,23 +569,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binarni" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "opis" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "prijevod medijske datoteke" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "prijevodi medijske datoteke" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Ova adresa (URL) je već zauzeta aktivnom stranicom." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Ova adresa (URL) je već zauzeta drugom aktivnom stranicom." @@ -620,76 +593,78 @@ msgstr "Ova adresa (URL) je već zauzeta drugom aktivnom stranicom." msgid "Other options" msgstr "Druge mogućnosti" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "u navigaciji" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Dodaj podređenu stranicu" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Pogledaj na internetnim stranicama" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "naslijeđeno" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "ekstenzije" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "je aktivna" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "aktivan" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "nadjačati URL" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Nadjačati ciljnu adresu (URL). Budite sigurni da uključite kose crte na " -"početku i kraju ukoliko se odnosi na lokalnu adresu. Ovo se odnosi i na " -"navigaciju i na adrese podstranica" +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Nadjačati ciljnu adresu (URL). Budite sigurni da uključite kose crte na početku i kraju ukoliko se odnosi na lokalnu adresu. Ovo se odnosi i na navigaciju i na adrese podstranica" -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "preusmjeriti na" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "Ciljna adresa (URL) za automatsko preusmjeravanje" +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "Keširana adresa (URL)" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "stranica" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "stranice" @@ -705,28 +680,26 @@ msgstr "Dodajte kratak sažetak sadržaja ove stranice." msgid "Excerpt" msgstr "Sažetak" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "navigacijska ekstenzija" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Odaberite modul koji će dostaviti podstranice za ovu stranicu ukoliko je " -"potrebno prilagoditi navigaciju." +msgstr "Odaberite modul koji će dostaviti podstranice za ovu stranicu ukoliko je potrebno prilagoditi navigaciju." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "navigacijska ekstenzija" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Odaberite stranice koje trebaju biti navedene kao povezani sadržaj." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Povezane stranice" @@ -756,9 +729,7 @@ msgstr "naslov stranice" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Naslov stranice u prozoru browsera. Podrazumijevana vrijednost je jednako " -"kao naslov." +msgstr "Naslov stranice u prozoru browsera. Podrazumijevana vrijednost je jednako kao naslov." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -769,10 +740,6 @@ msgstr "Nazivi" msgid " By %(filter_title)s " msgstr " Po %(filter_title)s " -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Pretraživanje" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Stvarno izbrisati zapis?" @@ -791,8 +758,7 @@ msgstr "Zapis ne može biti obrisan" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Zapis ne može biti obrisan jer je nadređeni od najmanje jednog drugog zapisa." +msgstr "Zapis ne može biti obrisan jer je nadređeni od najmanje jednog drugog zapisa." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -803,14 +769,12 @@ msgid "Really change template?
All changes are saved." msgstr "Zaista zamijeniti predložak?
Sve izmjene će biti spremljene." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Zaista zamijeniti predložak?
Sve izmjene su spremljene. i sadržaj iz " -"%(source_regions)s će biti premješten u " -"%(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -832,19 +796,21 @@ msgstr "Prije" msgid "Insert new:" msgstr "Umetni ispred:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Regija je prazna" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"Sadržaj je automatski naslijeđen od nadređene stranice. Ukoliko želite to " -"promjeniti, dodajte neke sadržaje." +msgstr "Sadržaj je automatski naslijeđen od nadređene stranice. Ukoliko želite to promjeniti, dodajte neke sadržaje." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Dodaj novi unos" @@ -980,14 +946,9 @@ msgstr "%(comment_count)s komentara." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s je objavio " -"%(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s je objavio %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -1004,6 +965,3 @@ msgstr "Potvrdi" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Hvala!" - -#~ msgid "Symlinked page" -#~ msgstr "simbolički povezana stranica" diff --git a/feincms/locale/it/LC_MESSAGES/django.mo b/feincms/locale/it/LC_MESSAGES/django.mo index a4fa53cb82c72b091541e8889201b717c7700f6a..12d01f0e069a8b2d2beaf9af47e7fd60ed102a62 100644 GIT binary patch literal 8514 zcma)=e~et$RmX3WhP0amnv^y_4DB_=*v31vyG{(rI=1Vd$r775_S&IoN&RN#&dkle zd2jmOn_chHq*Ve^N!6t6j~!|@R9hiF&7+L+&i|9vGt98b*{^9J|_ z@cZHO@M`!qcsYClF2HZW?}Im9Welgr!t3BJcm(c;uZ54mAAlc#Z-gI#UHCNA`&;Pz zb+8H5-vM|9JO&ZX9FN!cz?-r+tud>+0YejDohD^ObFUI*U}uZMcSjQ1ae>hEDFJs*X?0KW`p;Te>beIABQ_%v+8 z7vOGq2g=?IH=xG*eRv0a2CCo7udU_23SuI29hBYP1oeCml)d*s>2oJkKleaXF!w{f zm&WTV@?j`FJ`|rn7Vm!yO5dlT#`{dX{^Q6mK+VUW#p|y?_4BpJZ$!Qb_1?cleh13_ znqFg8J^);`5I{z5lUz{Ryb|o`UN4vruwA3voH~=TLI} z162RthL^$rfcoygpzQh*)HpMI%+#1`;TK+I%v+%Pdy$}*yN-U9Xg zI+Psmg^I^V;S&5EsQLI8D7pRzZiQFV*}GvA5(4HE@CNt{RDWNE8t3a!@_#d4|0A?q z|1;bVui+#0e;j@a-Up@kH8&db4tNt(e``?kJp^UP_eK5^lpc>kx-@?W)!%{8!-#_&EG^_#(UoKC;D_+u$F{UU%|6siT^HBZ#BE*HvuRzK91eATAj{GC2@1KR5|1Uy)_m@!p z{XLYQ{S(yp{|jZ0tKMA8dn4q}?25cA-d}-=#|NR_{~(n7k3)_BQ7Ap0fa>?tP~$xt z`8&eJZLOuU1)bnSchj$eVesQCtzJl}zm?==LMzJEPbyx#!z z{T8U_TjTXCRNU=`uYv>G_*jc4+aiAq9;Io$^0bsTKJJMpKMHS+=i8zB{t=pVAJTN( zUL*Xw1j49I>|I`qKKW?+PAv zY`4enE!|9~HAU!GdKzaAPweSK$!C zRz;GPh~x9j9POah^o?U-9?Y>cDf{M5J~vAPO~4X5M49P!)NZ@7?2ZtpX^y*O)mc=m zkgbaxTx3jjI1UdmBR&QosJH)YeDJaWu-^7d$eUgo6SD)_0iv8^IsE1CK=pLO!Jrahft z@}!J!wAL|NHyNcBy#&uOC$WHcYv$DH)3)neXY-^qr(BrecI`i7uQ_0EZxwcKe{lKm z2o11FiP<~N@kdi$e1LmB>{`!>In8_KG)~^GEjGwIqZA)2@>SoF;l}C)eJ%){^?YPA zWR(5eqY^Ll8z_(2Cl+g()BU`t+M}v8%kF$-mXUF#+zOd*Ul1UvCql5hJ{%-ItBo@o zuDf}f<`}OR-in%yTEW1WUY!(WNkqL0zAgA?Ob@*`%o@&h@8?Ii0>dyt$FVozi6 zWj#%6o@9|{gig!ZRbToR>SG?g(N~0oOp$a+K;d477GY}QV3LB7@r4kKDPh!E$4ysU zW|`n58+*6I>;sDuLltlC0-46qKqHTQd)N93Tc48sXnQThSCHmIgu1NjE06jiyL&Za8Yu1*!ZTbMD$Jt^B-AT4ckfk!_V#Y8#tmI7~^MA>SpdiBA*F z|5VZ|O*;uXz{>UV!aLmxr|U+m3_WRH1{YlLPMx>Mtle#LwLVlo`Eb4Py?$ldA^mo0 zDm>-LhM&Yt+0l?iGULe0#t|#2VP$mThYZ-w>$8$Dtj{V231_A8AyJ24F0v`N;VLeV zCM7&ZO6X+KY8*^P4rB(&`DR$bN;6>m#DxfoxY)E zAsBtrdCcY+UTBJBZL_1P^U^SaFGBvzIUgXWDSVr?L;0@cf#iuSO_`2*hNSuc4@@O* ztA9(-<7ZqAgs(%2GIgS2DVdywm8hMkqd{h-oR!LB`jYPC0i&S_kzW6XgixQBpiX$9 zxM+|jSb=hh)>!H^&bp#R_CumM9k3yIe{2*U!@pd;4JJtrDc~eAR6C z_w!Zl<&9;R3>NKDm870Dy<;i?29x@(J0H|xF_cNlx#6Zp<4BqF)!fdR6H6zKPOP=i zoS&hVQ}x+c#{P@J6Xt@0?$sJpki+(!Sw7adb@HB+=(?hDG;8NtcNgugEnjWQx=8HJ zoJ>b7YK>#$nsU)*!*E&d+r8J;r~7tfcI!U7uygN>Ig)(0y1Cc$qpat(rcv+`!@bn! z=HU2tHp*9XOEI8YCO6BYD*k%wqwkL@PvMyHmfXH#5(ygnE~b}ouDhKjN2|CT_>45p zDwSMVUu&(Ta3oamJ@OX=dfrvlvYNM5Q@-4zSvzz^yZ_wB?Q>63D|Gmx<86{6Zf-}c zv}sjLa+n|h$4yvSowemE(USd<@)(>OM-sx&R8b$L#uK=ibI zu=*(HA(Ivrr<`3aT#LmPgCrCh=vq;sqdt0-WT=9L^dQ4hOAIBRH%nt})9osS(1qMy zF{?p(iZ3R+jr+=&cvD@jOBagtq|gXyx*dn%bsH|^ofuiJY^wNO>a1P_^8bB=isBxZojB-UuJgGu<_#a7#`A=E6E{0Mk6Ya zx}v9)uh`_|TGjQPUiI?Zs#aK45p@s>$@^n*e-JN`k0qN`y*Z}(nPQ)KU8Q7Yih`43 zkLaf3`raxSgSmJhN1)7M=h{;!mPxuwAmTF#rBIq~I$iC@X(W1 zx=%IW2u;*6)eNCaRW)rfsd#Cevwc9UmM?Q0Koi7ky3yauX#t@kdG9>OmFyr@LA$N z00|Qk_6IRui8vHvY&-PNeU2FCzY6#r{{!H5-n3^(iP5_CWXI9VqO_=N=-N= z)MR(i$r%V~StxMx0kw7c zEr;EOF3xIyF>6Sx7k2dRs?`4A#N3IQ@C~Sx<%!+Tvnz4>;M%vs#zw9?!&{$Q2 zb0$TOMEvha|CN};D6w;v<&5N5=XtIQ&3O!I4ZZnamO9yMlH@=vB6y%uSoHRGQYr*B znzA|L;VtLRS!zl4Bov>)cNn@&g2*kN6spopUAqo1amaFr>vSv9X(XwEAwjUSm zNX8oypBU{#!m_B*>61;tC3nWlOl~G2rsOucU-@B3)RQ|GZB=rky-CoLol7k(cf6@f z`uYam{W&v^DB~L6ZOhWZQ!-V0+Bl~5wt~^abZzc#Ci@q*F(lQ=4yGPxy!7VUtgsZA zGbvmDi{j8wFQ=|oFTnMNCMno6=2%oC*#ZBFK^k^9D$2*E561j|o(DT!`uyTM{uOsT z`hQxez_jNXubh``dw5{#HOvsOtUhG&dhc_Ry-#fpyen>g^skfXi7q4jH)n0^j+-+V z*V_y4kFW5e$tjs`YBQuxC)=TLMX^o9YXJ!PkKNFK!jd`SY_cz^M=qV{!e6p6(yFl>)?ICg!m{n$ZZrH^9AEPqtTmS$7 literal 13731 zcmbW736xw%b%qNsV8r4L69O1NgM~&|)6z(?F=NR_(n#`vmO(R;u^o_Jcfam=sQbP4 zTV^zh*}TWtAz%pD1UrCPZI+mTF<=aKyg>+@U=Ac45;)0WJ%PiLg!LrfUsbQWH8L^e z9o_z4)vM*!t$T0Xx}$$N;ixwoo`;}kLe0k-^Q6ZZbK4VDYs|NfGv*}l+u$?6{|1i- zPvqw`a4D#!F9MGQ&j&TmMc|Xc1EBg{1*+Y8`Sqvkbh<^KNH|q@EGt~@bTcALCteB_$2Vd;8Vf7z!vy0$Uk%TiEe#6 zz-5%1;8VbB!RLbS0LAx%AWJu21)l(Z2h@B&1;x*=L9OQqIv3zE;8EZ!!N-A@`tmj4 zb11(aRQr#D8t+c<>EM0fTJT%o8Q@6>pI7r@@Q=ZLp!himGNri+)cW2A-UPlM)cVh3 zv1+#qJPX_liqE(D`kTRxly3tizaN9*b1lNwy4HajXEXR#a3?6fz6WaFlb>cx0FHrn z9#G@&1!-bhp!&ZGlpL=1->(DDr2HoEBJd0T`!W`%_A5ZOKhxvcpvHe8sPVUhlHZK~ zegG8TuLQM@E5Hrl=fNw$CnD4p;2S~d*WF+Z{0Z0q1C(<$csaNRyaUucKLoWuKLs`a zFTkzf(J1#ia68Bl<{D7zeK&~c&0V1O^DChE`d3ineHWBH{K$X*EhsrY{$#hmCxdK( zSq*C5Nl^WFg3|l*LG4T3<9<+l6`=P2wV>L+-k0Cv@!g>0`ceP=E?<8iC^>%x6u)2h z<$w41eNcS-2-LVg2gS#4K=JXoXSx2zfg1lLkEeKC4yykek1qfvhjT&ky9HFg8ILaq zHSR2^bzKaKzgKy@4AlHrd%PZ$ylw&||Br!M#}`4_=|6#*=LaCJ#QXx(cuP)k@;(-n z-#HD`xFewEUju6Xb)ec$`tLhHt>*$z>)7kdEl~YBpzO5t->(71#~Xb8J3+1Y4p8HN z4ivxt;LHE)%ijex{?9AsP@kXHO_ia?Iu9= zn*_zzE>Lo5fcjp7>UR*-ysrVZo@+pjdow7$KLo1%r@$k?&w}cAFDN-a1Zv)gL5=?n zaQ9=3`43RzZF;sl4_*rDdjYNluLR|NK}M7lJw`TA=i40fZHE z75Jy%2SD-t+@;R`&jd#(Zv(ZzCHOq>wV>8}8z}xi14^!61J&+3pyc*b@M!Rt;5_(0 zpyV;n;`RMCpvJihQ9s_P)?)caP?xZ{mw!lw-j|Wd-(Q3Ec<7)6W%4dU9 z;P*g8ZC-G?-$G=Klm;1TyWbe=fAG?c#FqRgHPo9!=T3bw#V;*)*k%# zqhLyY@OY0S9?u2UZx6Txd>JS?&U(x|UII$Luk?6>ufGk{JRb*-2fyI!zX@vG@A~>5 zfs(HdQOW&iP~VRSwf|4^Il+J|p~$AdovW&gkRc=8%ozaBh}`kkQK@AKsZ z6u++q2{Fv&p!mB9)cCi6;^S|?W5G}O@`K=sl)vQ5{|1V$AAsurGf?aJCHQpk$hA&R z&jK~ia!}{oCSQLMD85=A3y+tA8uu?i>GKVs#(f7UzHasPw|o2~sP)_fS~-DQ_m}o^V6JkJBQ{xMMeZve&bMWFUS1~py*9sw?Z>VJv< zeyJ~C2Wp(_L5>lVK)5LL8E7+f3G@<3zF5y5=tIysD)5}`z3w>!|$8@ zyWnNeMbJsm0qDh$p0`1N35}@0^IGWb(1p;)p$vKzGzIO1V(1>|8Iac3g0vqiAwBCH z*x$4G)!x1ydWWrH|G-Z{1tfW&58VLiDWO+F5wr!m3Az^2Bi-rRH+0aWpyS_j@D0%2 zzO1uI`k`kZbTKpwJqXD^eGIx9(sPUhv)$vLgX7R7bTjmFNY5yA6?7$ZE2QV|pgW<@ zLhGR#vy6O6hw5Yt z^N@VSCg`sqJ-0(oh8}=+L3%z2T>$+pGzZ-R4L_fw@Jwj8uiOhh71{`W1bQ!YB&6qP z=rm{sdJXg(=oIKl(5Imdke>UXpYCa?|N0Ud-M3tb1j54sF`KXf^C26O_XXARV| zZ|-M5@D#lU8yAA5BdxeoMA_aVE;`ZjJTOZ~8fmv1CB@!GS|$ZmzMR+0(q=&OC=cRp zFU^XmX_n@}Y?uf2C`y8EIu|vAA`QYIiROb|n#V<)CN(pXq(LL>sj%E^Xf{Pbn54yQ zl)=GVl-1Kb+M9%3IItfZvvH>x^ul&zi`}Rhhkk0tZ-hnEPO}C3O;g21)U|~}KDJnw z+0f~TSVU5=s33;Ca>~5CDO(u}Q>d|aC7pG;mA_&>dJncr6jA1v6 zUG^wwZ8(%7KP9IqP&sCR)Zv` zxGT+=h?{|=T_(*a%Zo5+N(C7f#`7X88&3N+HxYB11X`o9g<-xnALyy071|cKE;F=x zi?s=}r4#0}=DeBh+k&~U6F2Qjf?k$3%Z6pvSx7UO53_`M^I9;a{fmMunv2m(6db*w zAFV3|tVf-69`Q-RY-OC3^c`pI-6+plSk8jaL(u%>h1C2!gli_-iF#qWOHj~TNKVk0qRq*(=9tNYM3nq`D|KZeMod62oWN! z#4Ouib+Q`Zdh#Vuw^&{wv7_`d_J?sgsA|c2YGwzj(st5|4q%44G-3w=s$5IZWv+T8 zRYLqbFmdOD@HrIXq*oT!=A3<+oz`=tRv&V+bD)^WC(PPWA)BlP8zYu1nQ4edr$l#A z$9xu6u{24t9<}2{TZcQswq0e!D*|!G83vscYj6Y3Nb|#13uVOuFi<;4GFY8P$;-OD zNxn>dSb*4@m%lMn6I+62+9>5+%@l0{>vbjFpq{1kY+EoNC(U%e7EI#|13as1QD0ya zTVdHLYIKylFjFahVv`e-nabE#%S^6Kt(QfC#yeGG^;y)A_0jLoY3BI{Ec&Vf~K>)c>nJquQzV_mfUgn-#HEkkF- zz;3L|T8CYyN&B3oBRQ_85$(;`z%;>P)~)oPCDVEc=t-J=6b=yKCYLI@D;b3AuCN!x0 zj#F-QuR4vYIAh$7kYQo1IKnf+Mdj6VZ6EHTh;iNo2hDJy7HkN-mV1ZjY}n3~CY-BG zI2Y$}oqfO#wV+uYpH}Xnq83}1u=&=A{A5}OGvie3N!{U$Z7$&N_7i&HAHt+^)*9zg z8@uSjyZ50UTAL1O`6O}HjuI9qZ5nJkf=c}a1NFmE#>sxkFbvR~qGXkfF^6DMew$Ic zB8Y2IZ9JGQir)CjmGkrSHQ%s?yI(mU7LD0+=hh$WzG5uv9h}&8;VQS{YLj|d)I-^v zLW(!<62X3S;MscAF8iZ}`7~=CBGa@RlIP%SCE`DrLV2lk);HDS}0rJ zVA-&<&j&V9a~}#2HTKuj13_5F%4_BV8aC5pSwXmrgI4n-(qXKFvKM9DIG0mKz0&|w z&_TpbINxllh%<-|DC`beAwhVPh#_D63E5!(zTO4thqR7+cvpgJJc_oS2`#FqTR_4_ z2ZfwY*z0wO0&VCv^j<|V!{4hqhMI%1P-;CCVdbXI3A*3-3jklE2b-`4pJugWC zW759vAq5({(6vHm{)5s&PXngCg)DB*7N%h%(56G3b_&7_KcN}Y7Q<1S7|Gj2U3fQ9 zBKDi6AEo4`RRx8*`565WOtez>mg5oKTLA<1EjKPYwZ9aSA;Y2MuO5cob;f6^Fo_r3 zoOdjy6SWE>i!$BtK+Rqyax-vUL$AZa{vFlBJ@sDTs0KFUD!fJTIc>%*zxPgTx|o?E z^Y2T?5MvsJ;8yb+28-fmg}Ya@VebmM8_B!aAHQcR=Tz7*hRaKwnCh-*u<=pq83t9Z zw%m{Iz=e@^JBKS2v<)hW@tVed)*IGrvQW{cy#o%v=cYP&usq)FnVjkDwPxUyDd%89 zhm6PE~9XV`KhjG)k~j|#T9Cc@!9jj{RV`EgEt=# zb;@pHhD?l5Zn(%OQpU1ptlM?J);qh`9B`+Pjj2Yp@~JG zPG7Zp)hZf}66G-E;qBH2W6vL7J9hf2G1_fI|3_#1oiWYEgQ+m>q`?H2aK5>_#OO>E zcE^Kl8+L5ny@{Sqv3Kf&VjE2z2>Ecae^&--*6<7mh+6#If(DHHN6WjYty zOv^!}8`T1vYiV*-&AGJ1A?cQOJ1&!U+DMv?-4UQ$s$>Q%sOLCI=Hxu zShI`^j#dzzA%&>nTvVug3!c_xYT}ec3C0^Do4|6+$?4NHikr-aB;oEGa!*E%n1Gyl z)QP)F^Hk{zvHi&32@7>|BaY#~Zp^YR?{|Acj1+TGCm=yA9onQ~z{$DlRI5(AI5gY6 zhg}+w#tFN1a$7~*OZ^hb?8K!VsUBslh)fRg0UkT9c(r@oml^C<=`DE2v9m%yl%hAs z8MiXR=Sr@`X#GTwmW1L=Mcm`(5V{0Gbkc}f-|d`HjgUR)D~C3CXuDjhM<-CTv|QOd zk66X|lI3ZHu6DB%@*=J4=XY3`6>aPfXV+;`NgTIU26U=#H-M~960pyxO5TV|&h$#6 z+-5pT^rZb7mV-Ek7~GsI;iHYR;+;&i>}Hf43~ky6iMzDVw$LYi90xY%GK*lz{>VUB zN|pTy=j7ZFp)^rzm;RI0L6jMh78UXE28CE;s!$7a)<}yoKRYnp6b5yF%21XmtM|-H z3M1}?oGmsJ6b5Y>p`BWDx&+mLS9F+U5O*eH(?KzUvfjcfl(WuConV9+5uMEr5!vrh zsj@MtHDObrXg-wn4YaGt<%fOfhFlRyRurU)5D z*P2ML?BpTNh~!TPMY+BH^@6-mhSTf4}ia)axj4 z`{YC3*(f5nR}`hLLH&d0cTBSZPOY|@Ey|IQ=o-9CV3+uA$pGih983U@X_f5?boyBh z>Ca4BE@|uRvy0~=*NkDWQDw5wgu|0x!65tPf`uwfsCq3O`Q7=iJ!PtMb`i(+Kte0s zvHJ%wUNeUbI5=MYIgY_ckl&g{@;!lcL8l1;eC5D_WoPtwpv;U{#zvne#E?|nURl5oj1I|R+yBA6&K z0CB;sHNnxM!2J-4Nw6-z^q~-jBmjF{kMoqYzO0{SggyjT2M=1MJjBv#IPp2og6T$@ z;ZTb-jyT|CtV*>J0HBK*f6MB{l}w0nY>!9qSeB!>pK%+60>qy)@;PQ}hOI}Z;=Y|f zmJ*kUoPck@{R!F3}Fv+#GOWI-8P87B+!%q&r93D`T3ejKB0_V%= zJQOo3C1+(`g#1mTaxTiqxxi-VOzkOfxs!8+s2gv~Ukuolv=;1U&%MGp7v~qiwD(>X zFpfV;*!)2@F1OB-cvUO*2V_iyTg~Uf5jjj{yKBZfZAsl4VjE@x5^6f^Q8R_?P6_;J z`Fr$Ora1DjZk&FY4Wf2qOUYcO&M9TCT(Ap9h7OGWY)#IGs7`_or>&EXqsJ!i`1>ZW z_SPt!BxyBc(|9WEQ6g`JJiL6PvbBFuCeKU8OIvPUJ_b1<; zth1dkOW}&VmU3%@0h9%mmd0FoZDvogSU*DCgUM)j{OKlM4h@R!c1e#=L@9NTKZnOU zDH|dBD7Iaw$K)8ozJ2|em!Z%i_~5UE3M^ejWup}v4ax%bw>}~=p98e^-&ap|#Ci<= z=IRbL7qlo1sCdPOdI}r!Ke&E_P5u#xTp0I^J>i7Ly%C@r~d5D z7=^X=S{FQGH3sXFhORYA>+S>!iwNEmUAJPJ3~Z!ka78uMH8SeIg@dV#cduU5@S3_R z8*GUqTh(Vxxe_1X;LAO~RN@)^5bk2SC{qYSigDG1#GzXNHHY3uWX$*6sp;+I(?p{- zXIO;jNIHmAW5ee6?-cTLE<r1H4Jx};+N*0tCflfSBV&&J*V$9F5&!@n=C zi61TNSjoRH-9&%%Mi2Yq!dmPfTHWs0Oar+`?94@!sj`o{@8pBv*IxRa!yQr#EZ5gr zh)i`$HZB=C#eZCJlVHL=8>zo74JlBpbd0r diff --git a/feincms/locale/it/LC_MESSAGES/django.po b/feincms/locale/it/LC_MESSAGES/django.po index b38dbc4b7..71688d404 100644 --- a/feincms/locale/it/LC_MESSAGES/django.po +++ b/feincms/locale/it/LC_MESSAGES/django.po @@ -1,32 +1,32 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-11 13:53+0200\n" -"PO-Revision-Date: 2012-08-14 17:41+0100\n" -"Last-Translator: Paolo Dina\n" -"Language-Team: LANGUAGE \n" -"Language: it\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" +"Last-Translator: Matthias Kestenholz \n" +"Language-Team: Italian (http://www.transifex.com/projects/p/feincms/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" -msgstr "tipo pagina" +msgstr "template" -#: models.py:551 +#: models.py:510 msgid "ordering" -msgstr "ordine" +msgstr "ordinazione" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "lingua" @@ -34,81 +34,81 @@ msgstr "lingua" msgid "All" msgstr "Tutto" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" -msgstr "Genitore" +msgstr "Parent" #: admin/filterspecs.py:81 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" -msgstr "categoria" +msgstr "" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" -msgstr "Modifica% s" +msgstr "Variazione% s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "Titolo" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." -msgstr "%s è stato spostato in una nuova posizione. " +msgstr "" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." -msgstr "Istruzione di spostamento non riconosciuta" +msgstr "" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "azioni" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Cancellati con successo %s elementi." +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "Elimina %(verbose_name_plural)s elementi" +msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" -msgstr "contenuto applicazione" +msgstr "" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" -msgstr "contenuti applicazione" +msgstr "" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "applicazione" #: content/comments/models.py:24 msgid "enabled" -msgstr "tavolo" +msgstr "" #: content/comments/models.py:24 msgid "New comments may be added" -msgstr "E' possibile aggiungere nuovi commenti" +msgstr "" #: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" -msgstr "contenuto" +msgstr "" #: content/comments/models.py:49 msgid "public" -msgstr "pubblicato" +msgstr "" #: content/comments/models.py:49 msgid "not public" -msgstr "non pubblico" +msgstr "" #: content/contactform/models.py:18 msgid "name" @@ -122,18 +122,17 @@ msgstr "e-mail" msgid "subject" msgstr "soggetto" -#: content/contactform/models.py:23 -#: content/raw/models.py:14 +#: content/contactform/models.py:23 content/raw/models.py:14 msgid "content" msgstr "contenuto" #: content/contactform/models.py:34 msgid "contact form" -msgstr "modulo di contatto" +msgstr "forme di contatto" #: content/contactform/models.py:35 msgid "contact forms" -msgstr "moduli di contatto" +msgstr "forme di contatto" #: content/file/models.py:20 content/file/models.py:25 #: module/medialibrary/models.py:84 @@ -144,66 +143,45 @@ msgstr "file" msgid "files" msgstr "files" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "image" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" -msgstr "alternativa testuale" +msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" -msgstr "descrizione" +msgstr "" -#: content/image/models.py:48 -#: module/medialibrary/models.py:233 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" -msgstr "didascalia" +msgstr "caption" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "immagini" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "Posizione" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(no didascalia)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "file multimediale" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "file multimediali" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "blocco" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "sinistra" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "destra" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "tipo" @@ -221,28 +199,32 @@ msgstr "" #: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" -msgstr "Ignora gli avvisi di validazione HTML" +msgstr "" #: content/richtext/models.py:47 #, python-format -msgid "HTML validation produced %(count)d warnings. Please review the updated content below before continuing: %(messages)s" -msgstr "La validazione HTML ha prodotto %(count)d avvisi. Prima di continuarerivedi il contenuto aggiornato sotto: %(messages)s" +msgid "" +"HTML validation produced %(count)d warnings. Please review the updated " +"content below before continuing: %(messages)s" +msgstr "" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "testo" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "rich text" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "" #: content/rss/models.py:21 -msgid "The rss field is updated several times a day. A change in the title will only be visible on the home page after the next feed update." -msgstr "Il campo rss viene aggiornato più volte al giorno. Una modifica del titolo sarà visibile in home page solo dopo il successivo aggiornamento del feed." +msgid "" +"The rss field is updated several times a day. A change in the title will " +"only be visible on the home page after the next feed update." +msgstr "Il campo rss viene aggiornato più volte al giorno. Una modifica del titolo sarà visibile solo in home page dopo il prossimo aggiornamento dei mangimi." #: content/rss/models.py:22 msgid "link" @@ -258,11 +240,11 @@ msgstr "Ultimo aggiornamento" #: content/rss/models.py:25 msgid "max. items" -msgstr "max. elementi" +msgstr "max. articoli" #: content/rss/models.py:29 msgid "RSS feed" -msgstr "Feed RSS" +msgstr "RSS feed" #: content/rss/models.py:30 msgid "RSS feeds" @@ -276,55 +258,53 @@ msgstr "sezione" msgid "sections" msgstr "sezioni" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "plain" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" -msgstr "riga del titolo" +msgstr "titolo di fila" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "riga del titolo e colonna" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" -msgstr "tabella" +msgstr "tavolo" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" -msgstr "tabelle" +msgstr "tavoli" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "dati" #: content/template/models.py:51 msgid "template content" -msgstr "contenuto pagina" +msgstr "" #: content/template/models.py:52 msgid "template contents" -msgstr "contenuti pagina" +msgstr "" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "video link" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Questo dovrebbe essere un link ad un video di YouTube o di Vimeo, vale a " -"dire: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Questo dovrebbe essere un link ad un video di YouTube o di Vimeo, vale a dire: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "video" @@ -338,15 +318,16 @@ msgstr "pubblicato" #: module/blog/models.py:30 msgid "This is used for the generated navigation too." -msgstr "E' anche usato per generare il sistema di navigazione." +msgstr "Questo viene utilizzato per la navigazione generato troppo." #: module/blog/models.py:33 msgid "published on" msgstr "pubblicato il" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "Verrà impostato automaticamente una volta che spunti la casella di controllo `` pubblicato in precedenza." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Verrà impostato automaticamente una volta che barrare la casella di controllo `` pubblicato in precedenza." #: module/blog/models.py:39 msgid "entry" @@ -361,14 +342,14 @@ msgid "tags" msgstr "tags" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "traduzione di" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." -msgstr "Lasciare vuoto questo campo per le voci in lingua primaria (% s)." +msgstr "" #: module/blog/extensions/translations.py:44 #: templates/admin/feincms/item_editor.html:43 @@ -381,39 +362,39 @@ msgstr "data di creazione" #: module/extensions/changedate.py:33 msgid "modification date" -msgstr "data di modifica" +msgstr "" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "tipi di contenuto" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" -msgstr "data inizio pubblicazione" +msgstr "data di pubblicazione" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "data fine pubblicazione" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." -msgstr "Non specificare data e ora se la pagina deve rimanere attiva per sempre." +msgstr "Lasciare vuoto se la voce dovrebbe rimanere attivo per sempre." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "visibile da - a" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" -msgstr "Date di pubblicazione" +msgstr "" #: module/extensions/featured.py:9 msgid "featured" -msgstr "in evidenza" +msgstr "" #: module/extensions/featured.py:14 msgid "Featured" -msgstr "In evidenza" +msgstr "" #: module/extensions/seo.py:9 msgid "meta keywords" @@ -421,7 +402,7 @@ msgstr "meta keywords" #: module/extensions/seo.py:10 msgid "This will be prepended to the default keyword list." -msgstr "Questo sarà anteposto all'elenco di parole chiave predefinite." +msgstr "Questo sarà anteposto al elenco di parole chiave predefinite." #: module/extensions/seo.py:11 msgid "meta description" @@ -429,86 +410,100 @@ msgstr "meta description" #: module/extensions/seo.py:12 msgid "This will be prepended to the default description." -msgstr "Questo sarà anteposto alla descrizione predefinita." +msgstr "Questo sarà anteposto alla descrizione di default." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "" +#: module/extensions/translations.py:207 +msgid "Edit translation" +msgstr "Modificare la traduzione" + +#: module/extensions/translations.py:210 +msgid "Create translation" +msgstr "Crea traduzione" + +#: module/extensions/translations.py:215 +msgid "translations" +msgstr "traduzioni" + #: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" msgstr "" #: module/medialibrary/forms.py:64 #, python-format -msgid "Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)" +msgid "" +"Cannot overwrite with different file type (attempt to overwrite a " +"%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 +#, python-format msgid "ZIP file exported as %s" -msgstr "File ZIP non valido: %s" +msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 +#, python-format msgid "ZIP file export failed: %s" -msgstr "File ZIP non valido: %s" +msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Anteprima" -#: module/medialibrary/modeladmins.py:139 -#: module/medialibrary/models.py:87 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "dimensione del file" -#: module/medialibrary/modeladmins.py:144 -#: module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "creato" -#: module/medialibrary/modeladmins.py:163 -#: module/medialibrary/models.py:84 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "tipo di file" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "file info" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" -msgstr "%d file importati" +msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 +#, python-format msgid "ZIP import failed: %s" -msgstr "File ZIP non valido: %s" +msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" -msgstr "File in input non specificato" +msgstr "" #: module/medialibrary/models.py:43 msgid "parent" msgstr "genitore" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -526,11 +521,11 @@ msgstr "copyright" #: module/medialibrary/models.py:202 msgid "Image" -msgstr "Immagine" +msgstr "Image" #: module/medialibrary/models.py:203 msgid "Video" -msgstr "video" +msgstr "" #: module/medialibrary/models.py:204 msgid "Audio" @@ -538,7 +533,7 @@ msgstr "" #: module/medialibrary/models.py:205 msgid "PDF document" -msgstr "Documento PDF" +msgstr "PDF document" #: module/medialibrary/models.py:206 msgid "Flash" @@ -550,11 +545,11 @@ msgstr "Testo" #: module/medialibrary/models.py:208 msgid "Rich Text" -msgstr "rich text" +msgstr "" #: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "Archivio Zip" +msgstr "" #: module/medialibrary/models.py:210 msgid "Microsoft Word" @@ -570,103 +565,104 @@ msgstr "" #: module/medialibrary/models.py:213 msgid "Binary" -msgstr "Binario" +msgstr "Binary" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "descrizione" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "traduzione di file multimediale" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "traduzioni di file multimediale" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." -msgstr "Questo URL è già usato da una pagina attiva." +msgstr "Questo URL è già stato preso da una pagina attiva." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." -msgstr "Questo URL è già usato da un'altra pagina attiva." +msgstr "Questo URL è già stato preso da un'altra pagina attiva." #: module/page/modeladmins.py:41 msgid "Other options" msgstr "Altre opzioni" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "in navigazione" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" -msgstr "Aggiungi sottopagina" +msgstr "Aggiungi pagina figlio" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Vedi sul sito" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" -msgstr "Non possiedi i permessi necessari per modificare questo oggetto" +msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "ereditato" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" -msgstr "estensioni" +msgstr "" -#: module/page/modeladmins.py:167 -#: module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" -msgstr "attivo" +msgstr "" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" -msgstr "attivo" +msgstr "attiva" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" -msgstr "sovrascrivi URL" +msgstr "override URL" -#: module/page/models.py:265 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Sovrascrivere l'URL di destinazione. Assicurati di includere le barre all'inizio " -"e alla fine se si tratta di un URL locale. Questo riguarda sia la " -"navigazione e gli URL sottopagine '." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Ignorare l'URL di destinazione. Assicurati di includere le barre all'inizio e alla fine se si tratta di un URL locale. Questo riguarda sia la navigazione e gli URL sottopagine '." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" -msgstr "redirect" +msgstr "reindirizzamento" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL di destinazione per i redirect automatici." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "Cache URL" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "pagina" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "pagine" @@ -682,167 +678,156 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" -msgstr "estensione di navigazione" +msgstr "" -#: module/page/extensions/navigation.py:102 -msgid "Select the module providing subpages for this page if you need to customize the navigation." +#: module/page/extensions/navigation.py:110 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." msgstr "Selezionare il modulo che fornisce sottopagine per questa pagina, se avete bisogno di personalizzare la navigazione." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" -msgstr "estensione di navigazione" +msgstr "" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." -msgstr "Seleziona le pagine da elencare come in relazione a questa pagina." +msgstr "" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "Sito" +msgstr "" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" -msgstr "pagina collegata" +msgstr "" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "Tutti i contenuti sono ereditati da questa pagina, se specificata." +msgstr "Tutti i contenuti sono ereditate da questa pagina, se somministrata." #: module/page/extensions/titles.py:13 msgid "content title" -msgstr "titolo del contenuto" +msgstr "il titolo del contenuto" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "La prima riga rappresenta il titolo principale, le righe seguenti i sottotitoli." +msgstr "La prima linea è il titolo principale, le seguenti righe sono i sottotitoli." #: module/page/extensions/titles.py:15 msgid "page title" -msgstr "titolo della pagina" +msgstr "" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "Titolo della pagina per la finestra del browser. Per impostazione predefinita assume lo stesso valore del campo Titolo." +msgstr "Titolo della pagina per la finestra del browser. Stesso titolo per impostazione predefinita." #: module/page/extensions/titles.py:43 msgid "Titles" -msgstr "Titoli" - -#: module/page/extensions/translations.py:171 -msgid "Edit translation" -msgstr "Modificare la traduzione" - -#: module/page/extensions/translations.py:174 -msgid "Create translation" -msgstr "Crea traduzione" - -#: module/page/extensions/translations.py:179 -msgid "translations" -msgstr "traduzioni" +msgstr "" #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " msgstr "Da %(filter_title)s " -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Ricerca" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" -msgstr "Vuoi davvero eliminare questa voce?" +msgstr "Cancellare questa voce?" #: templates/admin/feincms/_messages_js.html:4 msgid "Confirm to delete item" -msgstr "Conferma di eliminazione contenuto" +msgstr "La conferma di sopprimere la voce" #: templates/admin/feincms/_messages_js.html:5 msgid "Item deleted successfully." -msgstr "Contenuto eliminato con successo." +msgstr "Elemento eliminato con successo." #: templates/admin/feincms/_messages_js.html:5 msgid "Cannot delete item" -msgstr "Impossibile eliminare contenuto" +msgstr "Impossibile eliminare voce" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Impossibile eliminare elemento, perché è genitore di almeno un altro elemento." +msgstr "Impossibile eliminare voce, perché è madre di almeno un altro elemento." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" -msgstr "Cambia tipo pagina" +msgstr "Cambia modello" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template?
All changes are saved." -msgstr "Vuoi davvero cambiare tipo di pagina?
Tutte le modifiche vengono salvate." +msgstr "Davvero cambiare modello?
Tutte le modifiche vengono salvate." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%(source_regions)s is moved to %(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Davvero cambiare modello?
Tutte le modifiche vengono salvate e il " -"contenuto da %(source_regions)s è spostato " -"%(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" -msgstr "Nascondi" +msgstr "" #: templates/admin/feincms/_messages_js.html:13 msgid "Show" -msgstr "Mostra" +msgstr "" #: templates/admin/feincms/_messages_js.html:14 msgid "After" -msgstr "Dopo" +msgstr "" #: templates/admin/feincms/_messages_js.html:15 msgid "Before" -msgstr "Prima" +msgstr "" #: templates/admin/feincms/_messages_js.html:16 msgid "Insert new:" -msgstr "Inserisci nuovo" +msgstr "" + +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" -# TODO: nuova/o? -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Regione vuota" -#: templates/admin/feincms/content_editor.html:15 -msgid "Content from the parent site is automatically inherited. To override this behaviour, add some content." -msgstr "Il contenuto della pagina genitore viene ereditato automaticamente. Per evitare che ciò accada Aggiungi nuovi contenuti." +#: templates/admin/feincms/content_editor.html:25 +msgid "" +"Content from the parent site is automatically inherited. To override this " +"behaviour, add some content." +msgstr "Contenuti dal sito padre viene automaticamente ereditate. Per ignorare questo comportamento, aggiungere un po 'di contenuti." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" -msgstr "Aggiungi nuovo contenuto" +msgstr "Aggiungi nuovo elemento" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "Aggiungi altro %(verbose_name)s" +msgstr "" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" -msgstr "Rimuovi" +msgstr "" #: templates/admin/feincms/fe_editor.html:40 msgid "Save" -msgstr "Salva" +msgstr "Salvare" #: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" -msgstr "Interrompi modifica" +msgstr "" #: templates/admin/feincms/fe_tools.html:33 msgid "edit" @@ -858,40 +843,40 @@ msgstr "su" #: templates/admin/feincms/fe_tools.html:37 msgid "down" -msgstr "giù" +msgstr "giù" #: templates/admin/feincms/fe_tools.html:38 msgid "remove" -msgstr "rimuovi" +msgstr "rimuovere" #: templates/admin/feincms/recover_form.html:8 #: templates/admin/feincms/revision_form.html:8 #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" -msgstr "Pagina principale" +msgstr "Casa" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "Ripristina cancellati %(verbose_name)s" +msgstr "" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "Premi il pulsante salva qua sotto per ripristinare questaversione dell'oggetto." +msgstr "" #: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "Storia" +msgstr "" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "Annulla modifiche %(verbose_name)s" +msgstr "" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "Premi il pulsante salva qua sotto per annullare le modificheeffettuate a questa versione dell'oggetto." +msgstr "" #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -899,11 +884,11 @@ msgstr "Scorciatoie" #: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" -msgstr "Chiudi albero" +msgstr "" #: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" -msgstr "Espandi albero" +msgstr "" #: templates/admin/feincms/tree_editor.html:38 msgid "Filter" @@ -911,16 +896,16 @@ msgstr "Filtro" #: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" -msgstr "Modifica sul sito" +msgstr "" #: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "Aggiungi" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "Aggiungi file multimediali a categoria" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" @@ -928,32 +913,32 @@ msgstr "" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "I seguenti file multimediali saranno aggiunti a categoriaselezionata:" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "Aggiungi a categoria" +msgstr "" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "Annulla" +msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" -msgstr "Carica un file ZIP:" +msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "Sovrascrivi" +msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" -msgstr "Invia" +msgstr "" #: templates/content/comments/default.html:10 #, python-format msgid "%(comment_count)s comments." -msgstr "%(comment_count)s commenti." +msgstr "" #: templates/content/comments/default.html:18 #, python-format @@ -965,17 +950,16 @@ msgstr "" #: templates/content/comments/default.html:28 msgid "No comments." -msgstr "Nessun commento." +msgstr "" #: templates/content/comments/default.html:36 msgid "Post Comment" -msgstr "Pubblica commento" +msgstr "" #: templates/content/contactform/form.html:9 msgid "Submit" -msgstr "Invia" +msgstr "" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Grazie!" - diff --git a/feincms/locale/nb/LC_MESSAGES/django.mo b/feincms/locale/nb/LC_MESSAGES/django.mo index 46e9ef5c66a9134b43f9bf7abeb746d8e39500ac..5fef81caf0ae87e2f2257b7716aaa496c9d58abc 100644 GIT binary patch delta 4329 zcmZA332@Za0mt!|1Co$n2@pcUkqst+ge=(&0nLKQk%B-fQ3Mg>Si&Z32)i*^NNB~? zQi?|f>!MYIDQ5-2)Vf5$3=Ya@twVvfz`!UTgDtDZ|!HhLfv(jQIvnrt`yg52xWkti~!_j;Xj8)9@u^Z00rW zkH5tscn<6EOVsuA`OyUGun6zR3==kH4+REeUd9xB6E*qYp*lK;8sLYhnS74w_%9g3 zYnY4;gW?A9M(QEd`Ol!*>%d%m5i9U*oIwBPpA<9$*I;A#XQuL_C0t$P&1j06LA$T!FJT~uTbaz%hvmHKh<73YCuC#=jCOy{u)sMJF2i0H{*R+ieI5y z$A=m-4i{oAZpL!_GmgjMERPzlK`r^+s1BFnENnpCf>%)ey@5LaogCI*2Y$~E&HN&= zisrA#;7uaa)CD=HhcO?ubfwk_sE($fR%$Nl{CjNOYYn1SWTQR4#qQr0rl6&G9yO5N zw%%!tqGogiV{Cd;_ZEY}EM$sN=<`nN*-A;IZ{-sOx5-+O4t2eW-yn#`bgnH&W0{pG0-A z12y6Uw%%pyZ=pIkg*yKnY5*UhZp{@`hdrnPeq;BW5%JeK6*bUoR68RuS?_-V1zlK- z8d*8AG-ifQzy+ua7o$2}ftpbR>N^oe4SXx={B}&lov7>fpayyX)$w6e``s8mlfctY zVL3ZG^5UP!>o}77U`PDZIUYw-pNW+iKt6hAKWZS|sE*E{25=sA-utLqnUx>kpMx5} zNYvX_n9u#!j4Rophh`4WK`&}W4q3ZUGk*j1rF<7zU2_5N!E2~?=8cNCvjW*=T2TXh z*4l|0zzI})?~P*p)zMjd;1X&kpVNv2{SoP&H_O%1xyk9F9N$(YCkq4QHP2{Tax z&q57o45}Ts^(LH3{T6%#A3)j-o76GJ+{6wK7GpCu;tnjwG@=#qv#1sO7*puqd`2NQQhT6B2iX4)>vhxs`;Ltdus>>m zLs1Roqs}ix4b*AtlThu>u+B!cGY|C)EyS=+sHLC={q}@r)XX-ZM*cABHF_L%-frZ- z3g#f{wS5!&;RVz!`4qKMS1}!vdGgfG08~3!n205%tiL*PvO`NZ88dJu>Vo;Gh8JOM zpcosdtvB0x8|q3@HIOm&~#^+Oy+=96Z-PphJB4GHW0*S3=!QGreOTU$GE z#Y*v?&Hq(av571sPmrg{BV-YoLBE8J4^97!VkiN2D(+gw|y!VRQ@Odz94Ety5u6KzLH*vHQh)!4R>TZtaL z-DDRTM;4RSM4KMI9P${MM=DA0rYHSj@*A?s?$leQZ4_Ba9wgdY;@I`4(nadYUg9O% z#*$95R292z!sTQ;d6fKsM95v_|F;+Hj-TRIl4k1*@cXec{by2`ZV!}Tqb)aJkuASy zz0;~c)z6T8@(Q_+{EYmPyheUb_)nE7BiW>t^e5Hic5*j4L-?27SDx64^R!Qpm$ z+~s3kA^K? zPwZ=S^mg3Z+Bz=O>wImo{+pVE4Zhk?OIg!*Lum8{>eqSeePw}_WyO)Uyd@dc zc8|vqSQ+_aUPR0Uis zPyq|3END#uDJ6hn72MJSMJOY-%}i^m1C~;R4ue>=j%}fxwzjnYFMD7Z@9^#Ko^$U# zulpdIm%Oz!czIC29TwXeGK^$JTb9jcS^06QwXDKK%X$=x@IKszsdy0Y#j}`&AD}Mz z631hI4i3c0sQS4Wh0Cxny0FNyg4POipcCoa+G9L`DU@Hw0r(3Xgzw>0yoUWTm&$vv z7!z;;#$yd8<05Rp$B=*41%5P<&u|p|Teh!7Mwo*P-YUZwoQ|Bw68qs7#+x{T^1o2$rzJ(&8-YV9kHJ#O#qj(QK6+eWKQTojqn`m zUSGlum^qkP-~lYsaV)@SmZcucuoz#$68tr)eT`1HAO_WOJXWiEDC@6#yqpSk=tW)7 zj;ddaT8T}_s$08|$yslr8tg`0*MoXUe}`JptH#ez9o|H(pp92Y=O>`bDM7O{617An z=7fo+ei~{C=b;9)(3D+94{9J@RKo$|8dJaClsBUWxD7SHU8r`0``J;)hm1#!r?Gd2 z#vatloJWoP66(57jWzeODrJY;Yt2H==)b*QC=Xan6*ohiI7wT3W!v1>y!|Z6JC(VH~ zsQ11bb-@KxgO^d~eS{kDr>FtmK&?=}^vLmK)OD$-0c4_9EDzOgC29h5FsKHXu+s;f zs0&@F5wApbyb9I98uamh!&ZER@~w=>r*xT}`${>0`oxAX8~39+d>6;#hp6KznUMjF z&gA~9!%0+VAk$DM&P3hY^`?F!Y9L!suj6*q%nzbo$KyB?e~Vg~)Zr1cP%Gd-eObpM zciXDQhtV~h^;bius8B;aNE_C5)ROh*t0dD<11Lr{I3Cr}6jNV=n#eqJ{9$aRTyN^n zp(c0{N8%Mz9~I1s+>2P$2nVCS**T~$nA6nnz}}}GwWKFZxf`|gmr+amU(^aE(u;0k z7QTpMQ1|?oI0?_8CJ;;-6=^UHwG#QL3n!vpzZsa151HfZ%<=800l$n|kvA|3k7GYP zjeMQ0v#3w?huDA#JQzCOj$9YCR$j zhHju9u78{Q7# zpcpc)PtccTXK3aZ^>sCG`F2K1{SJ6fXisHM4NyoMU-pN)S- z&F~+n^J5Dl10IB0iB#0B%SH_#&sdJ?xC(V$HEIC0sP=*j+0l}=U_7oxb^IKv!46ad z+ff&Gq6WGTwGywP4Le8%IY2x_n^sO+E7392JWD2!A8YGB+^cPM7~W%kq5|Ll1FZDkFrxso+6KsljK`O+d$p_ z6_I^wJMJdWlW&myckBHtxGvXMlSEkxV&2zP#~@9afBa$S@g)z~cJA}7c) za)=Bfb>w9-kED>zMB6iD0Xa$%$q&ixEuNk45dD|iMB+#id5LICCk|3VeoE@b@H3hm zA=-+`%HBQxK*Viip($@QihIcurtCF7hM`>#@^ub+nuWdz7}V|Q*ZaXT^_%?KG0SWPEYx=Pt@{eUwu<}@X%^o zUw1vSXAsN9Oo!1w-=48 zC>k4@m7W?$O}V3}%w9OIqB!JFugR>bs;!=1RXxo#_4Tb)>MYut-1c^l z%k6i!xxFrTbDP^=5H8Ff)K{}, 2011. +# Håvard Grimelid , 2011 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: LANGUAGE \n" -"Language: nb\n" +"Language-Team: Norwegian Bokmål (http://www.transifex.com/projects/p/feincms/language/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Language: nb\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "mal" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "sortering" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "språk" @@ -35,7 +35,7 @@ msgstr "språk" msgid "All" msgstr "Alle" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Forelder" @@ -44,50 +44,50 @@ msgstr "Forelder" msgid "Category" msgstr "Kategori" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Endre %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "tittel" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s har blitt flytta til en ny posisjon." -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "Forstod ikke flytteinstruksjonen." -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "aktiviteter" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Slette objektet?" +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "applikasjonsinnhold" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "applikasjonsinnhold" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "applikasjon" @@ -144,65 +144,45 @@ msgstr "fil" msgid "files" msgstr "filer" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "bilde" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "tittel" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "bilder" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "posisjon" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(ingen tittel)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "mediafil" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "mediafiler" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "blokk" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "venstre" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "høyre" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "type" @@ -227,19 +207,17 @@ msgstr "Ignorer advarsler fra HTML-validering" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"HTML-validering produserte %(count)d advarsler. Revider oppdatert innhold " -"under før du fortsetter: %(messages)s" +msgstr "HTML-validering produserte %(count)d advarsler. Revider oppdatert innhold under før du fortsetter: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "tekst" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "rik tekst" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "rike tekster" @@ -247,9 +225,7 @@ msgstr "rike tekster" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"RSS-strømmen blir oppdatert flere ganger om dagen. En endring i tittelel vil " -"ikke bli synlig på nettsiden før etter neste oppdatering." +msgstr "RSS-strømmen blir oppdatert flere ganger om dagen. En endring i tittelel vil ikke bli synlig på nettsiden før etter neste oppdatering." #: content/rss/models.py:22 msgid "link" @@ -283,27 +259,27 @@ msgstr "avsnitt" msgid "sections" msgstr "avsnitt" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "enkel" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "tittelrad" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "tittelrad og kolonne" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tabell" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tabeller" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "data" @@ -315,23 +291,21 @@ msgstr "malinnhold" msgid "template contents" msgstr "malinnhold" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "videolink" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Dette må være en link til en YouTube- eller Vimeo-film. F. eks. http://www." -"youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Dette må være en link til en YouTube- eller Vimeo-film. F. eks. http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "videoer" @@ -352,7 +326,8 @@ msgid "published on" msgstr "publisert på" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." msgstr "Blir satt automatisk så snart `publisert`-boksen blir kryssa av." #: module/blog/models.py:39 @@ -368,12 +343,12 @@ msgid "tags" msgstr "merkelapper" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "oversettelse av" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "La denne være tom for innlegg på primærspråket." @@ -390,27 +365,27 @@ msgstr "opprettet dato" msgid "modification date" msgstr "endret dato" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "innholdstyper" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "publiseringsdato" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "sluttdato for publisering" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "La denne være tom dersom siden alltid skal være aktiv." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "synlig fra - til" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Datobasert publisering" @@ -438,19 +413,19 @@ msgstr "meta-beskrivelse" msgid "This will be prepended to the default description." msgstr "Dette vil bli lagt inn foran standard beskrivelse." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Søkemotoroptimalisering" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Rediger oversettelse" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Lag oversettelse" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "oversettelser" @@ -465,63 +440,63 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Forhåndsvisning" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "filstørrelse" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "opprettet" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "filtype" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "filinfo" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "%d filer importert" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "Ingen inputfil gitt" @@ -529,7 +504,7 @@ msgstr "Ingen inputfil gitt" msgid "parent" msgstr "forelder" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -593,23 +568,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binær" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "beskrivelse" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "mediafil-oversettelse" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "mediafil-oversettelser" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Denne URL-en er allerede i bruk av en aktiv side." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Denne URL-en er allerede i bruk av annen en aktiv side." @@ -617,75 +592,78 @@ msgstr "Denne URL-en er allerede i bruk av annen en aktiv side." msgid "Other options" msgstr "Andre valg" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "i navigasjon" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Legg til underside" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Vis på nettsted" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "arvet" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "utvidelser" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "er aktiv" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "aktiv" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "overstyr URL" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Overstyr mål-URL. Inkluder skråstrek ved starten og ved slutten dersom det " -"er en lokal URL. Dette gjelder både for navigasjons- og underside-URL-er." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Overstyr mål-URL. Inkluder skråstrek ved starten og ved slutten dersom det er en lokal URL. Dette gjelder både for navigasjons- og underside-URL-er." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "videresend til" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "Mål-URL for automatiske videresendelser." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "Mellomlagret URL" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "side" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "sider" @@ -701,28 +679,26 @@ msgstr "Legg til et kort sammendrag av innholdet på denne siden." msgid "Excerpt" msgstr "Utdrag" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "navigasjonsutvidelse" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Velg modulen som skal bidra med undersider til denne siden dersom du trenger " -"å tilpasse navigasjonen." +msgstr "Velg modulen som skal bidra med undersider til denne siden dersom du trenger å tilpasse navigasjonen." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "Navigasjonsutvidelse" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Velg sidene som skal listes som relatert innhold." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Relaterte sider" @@ -763,10 +739,6 @@ msgstr "Titler" msgid " By %(filter_title)s " msgstr "For %(filter_title)s " -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Søk" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Slette objektet?" @@ -785,8 +757,7 @@ msgstr "Kan ikke slette objekt" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Kan ikke slette objektet fordi det er foreldre til minst ett annet objekt." +msgstr "Kan ikke slette objektet fordi det er foreldre til minst ett annet objekt." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -797,14 +768,12 @@ msgid "Really change template?
All changes are saved." msgstr "Endre mal?
Alle endringer blir lagret." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Endre mal?
Alle endringer blir lagret og innhold fra " -"%(source_regions)s blir flyttet til %(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -826,19 +795,21 @@ msgstr "Før" msgid "Insert new:" msgstr "Sett inn ny:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Tom region" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"Innhold fra forelder-side blir arvet automatisk. Overstyr dette ved å legge " -"til innhold." +msgstr "Innhold fra forelder-side blir arvet automatisk. Overstyr dette ved å legge til innhold." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Legg til nytt objekt" @@ -974,14 +945,9 @@ msgstr "%(comment_count)s kommentarer." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s sa på %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s sa på %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -998,6 +964,3 @@ msgstr "Send inn" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Takk!" - -#~ msgid "Symlinked page" -#~ msgstr "Symbolsk linket side" diff --git a/feincms/locale/nl/LC_MESSAGES/django.mo b/feincms/locale/nl/LC_MESSAGES/django.mo index 068a040aed4600dab8542b13ca3dc85b218e47f8..770fa02e7025413ad18eb99c11b3dba766292f8f 100644 GIT binary patch literal 15507 zcmbuF36xw_na3}iN>o5ZL>7Gru@gvDccM|~BtTXYNJvOG35!hfs_IqMOI5vB^WLlO zbUO?p;;!QcxG*@(pg1xP>WB)CD~hMq~??zi2q^21{fzuxe92s#=1^%IO)e26h$d8*zTv-emC48doBp9N0>zXLuE z{55zw_=Kk$a~OCgcs4i=YQ7je3Va2qao2-S0Y3<8+$X`K!5@Q1fDeP3=eOW;@b~`x z_;IX3d!@(K;4^8j2N!`?`1f@XmP`lS0KOCq!Ow$F0>{|Ik>CWVbtge>^#bsC@KUf2 zrl98eHpoBoGyaT$e*l@vjM4dd;A&9&se;FVUGRzEHQ zp!oSFSb#qO4+nR$InA>hRC^D28dw80?p2`Xe*<_T_zv&|;GN(~@V`LqFF3*RI|1q( zHv0B7_$=BnDE_Yn5w&?ED0$op-VA;S6n_`fS^cg6&jOpE_Hm1U|6Xt%?K?rq{eMC6 zzXs;C?~S15xd?m*cqu4;9|pDV5|kqVSA$yTN>F_41GUb6kS&?3LCtd`D7oAMGKF~$ z$dcwW;0wWrz$?IGQ9|`gK#j|N`zntw1GU~OL9O#vFazHSJ{vsh6t|BOsCicU_9Qq> zdmX6#-UzM*zYksqKAXYIz*|A-@dIEPJnT8>3b+DX0p0*UAN(S?6#P9XKE?uf&Sg;i zy#PEPTnnxSUkz&C_kxnkk3dw@{1%j69DSs|wD-PeHXf205YCQ$pi4b*<#@7o^+HSTUu^WNjX{|+cV{@uU- zZ&3R@;&eCv(V+M}*|(SY_DWFmuLaeAGbsLcf;yioL9G{ohl7cKpM%o3mw@8)HK68s zBX~G?BdBpVf#U1kpycuq@Nn=xP~+|gweB}T?dJ!e=KU2Yxg4_C^*;(cl=jm>jXNF` zpC^M_cMR10W$<%{7;_%DhxQR;Zr%u#JmP!$>l9S{x)$W9%?;pQ@NQ7@JLyappU(ib-ua;X-5jX>y$uxq zcY`{g2SD-nAE4y&OYnu@AG3Q+5=0$&7f1?4AS4l1sF43xa@1GS$YfbxGo2NA6~wCvuW2@(p-q;Ky6 z-$y$F#m6z@4o?Bs(>?3iy6-3_K5f5S09m zN4S!I3DkZs2F2%DL#*P2ev<>Fo;%9$Nnf@M!Q| zpys;+l%CxMJ`Mb&fB$uGhW7VBo%6*AQ|HwMwclA#^IZjA1ik{i0DKVK3I;DA7Jwa) zDa`M{v%&I8rw2{2OZ#1*=`Gx#fT5?sY$i@zC= zP-w0Pp9kIvN`Bu5HP25y{t`Tv_HRJx&ygf2Y99wa9UKFn39bTl-cug;f|6GU)V^my z$^WIG#=i;FI=6yP1#kCw7pQSx0Ci3efLiyvpyd9apw{`BfBzd$^B;n+G~XhRPXi@~ z6F`l7HmGr@fm&|@)V$|_T4xI=zAgrJ-ZfDD3sC%A1FGL^L5+Kh|Ndr=xBKru2CDz3 zL9P2GP(;*zr3E&B!zF!VXzt)11+Y~5y*Fep?AC#V71!|vf z0mbjzLCNDipys&)lw3Xq>U{6@-+u$txQ9T^_ajjI`w1vMe&O3sT;=9D8WbPT0kzJA zf4>IQyxTlp=HExY-2*l58c_0mGbn!E4QjoA0=52!LCNhdQ2p-##oxC;?dN--`u*6q ze+sJK|A3Oyp(JhUf1Jk?LCqI{TK5c4@?Haq-wQ#_w;R-Xz8KW_hHrO3@wp$A+^+@+ zYbJnL(mV)#4QfK0Ak@$_pgW-NKz|SQKeIgC4SgLF&lyyK{u!Ep#HVyb{!zAhDWuQm zp~OBRC-57PY)zk=pk2_Xp%Bt%H&j4lkoNj+NFVK2pA8PIyuQTq+acV7c^UKy=mtoi z2O#-k`G+?^^UyWWosd3?H~r6F@lf)OX>bmDy>D*=WB+^}__xq2efuLG{|;Ebyz)C!v#} ze}Sa$e*^s^q|ceqNs#pAi;zASK;MKu1AP>#LLKOKNS~KGuz%mg-w*nB-6Q5^{uO!^ z^lj*kPzrq<`U<4a4(K%KP)Ihak8EQfM7XeVcPIE-NS}XmVC_u4;zHl9uu^N1qK@UM6g5C?2A$=}#V6F$B4{h}A zD?MHfegRqvoeLcY-37@u`=6Wr!+qd7Xg{>rzk9#OcYw!2E1_5WcPqdabQ`o9dMor< z=p5*C(8r+d&?V5@Abon!hwYOwF9mDRbK75ylPe74>@lNnH&@Iqk`*&^OqTnE(#Y?JbrxPW` zo?aehN!W>&=0P6DwIEG`;g@-@(us>bwXop()s-w5Kj#tCnPA-?lo zP0D6%ttR4qC5xka5bdu1ha9`3~F(`9@()v?VyU<8MTK!)8zP9$yD_C))o zD0Z-3A!he#DJyvKuWyD)BMKJh#y@GgHs6}{X}cYEVY|p8wUTk)?hlW&AF$UupQ$;#CbPMYrQHGkav(* zs0FiOmcVgd4t7Ylq9BWAV$4g1-0RBo)CML}iQ4Hbf|v5!mvPc#>?G55qC7_=IilLk z5%DK4WUZSy7PF<1XoRM;yp3?wU*2r765W#E4h#96NwWpb^18$E_NrBusP|Bdve_Di zGf^NtMn~jjXe3287v#;fhZEr}=7JFM(@V@^7yUt2cic$6vBP3{!o<$f%{W=+X`|#l z>$bMV)hx}^dJ*WL+Gg0^k?Fx>cbbJ5 zB?q66X$%_>d)5h=9UC?UwY1t(oHIM<6WHja6Cr}6vm7~S|jI&?!w(qgU;cAg8w?r=UFR~9 zle2p%uY%AfNBjai_n8td{6rwRxQJC=}O3+`<5KHL9 z^UkkN+3-Ke4{YMn?Y8G88KlI(W)xBu)ZM!WED!%LUeLJAv*iU}?hli_ba0nMPTb~9 zT$9=KmEG#F)ePyr%x5m`;kK9({j2tHelX}<-q2n&cTzJ`O`LnRSLAw{HB$-;Q$^Yh z6dPE@OxdRUWtDn|VFFeGS2{5i5!ezX)5e4GOj${!s$I9A*v3e3dQVS@u`7<(|& z=x-}O)l4I(1zIb~rCCf*9LY$i8>X1mv>Q87sW0B1SYNdv+o=aD@t*tvn{VsH(Q)t5-FM>+_0z*q8V#G;HG7Mz|MUP!F#|(l=`CE(9WkFny%9BB}D7us53)UF>G4Fg`XABL+#CXX`PCw4%9LLbSF2 z{urAwIQ3%>?G#J&2iS~}0gh+ROiSr< z&dh}~)4z0ZC$pJjJtX6=k(lKNeuWfqdj7q;{{^GHNiDTwGAAP?VL^*(>Vlb|5UGi*v?b zfJ2;=UJZcWw}ss?N1(oIlN%4YLgU6|#W>>q!YYUjMLxght=I5GXgguy?Qc+WH_ zcV89!><(NmZjX8Ng)-maOA_Upv0v*6`!-pql-(9HMxS%TLNQ6E@o0KmDt9|6#z*fiKh-o3sJP{S8R4 zhfhAWZ1*~e8L>Q);?X9vNGE$;WBs=KYu&qh%mEj^Y<61G_IG5dHdESCEA4Wb_GGXr zij(!*rWWmtwBK%qWKjai$Ge05^bK`9X^$^mv~A0_jYC;2FHbC5?{us*jr1q25{+9GU!{B^ zBe1NwWO`HStYJTGfznQCV^YQNbOS%D5*GtbCxfKDXooFbls4g7a$dMfM!sgns=z(2 zS&{^&t_hYeUA5>>s8P;GG3mF>LtXt6Wquqb%IzA0CmbnJnnzYB$!xF}?0j*JT*($x z$Z;CcJ$JY|WyIZjG0CXC)FGj;$hpbwN+aryY2+SM!EC9h$(@Re=L{#T{E+Xdhe70$ zoO7=h%#b+MB64($k4#kyR-0M8uil?BNgIJ?JMeBYT+7`CG^lTdG4Zvt$5=3zh63Ol*9JmtE$SVS(_x>uAkbD+{cgbk zDbHxhR1+MmUK&RRg=MInoefQUmp=MVN2c?tHj5S&RB~Mk%rhKZ++de>i&i@5^r&pM zjOwwIK*{T}JLP^h%06X8w`cWQIk1{DAGIm?xbad^R~HUQ`Afpi7^yY!3q)HU4GA2#Svvgs znktDgdV>1t^RaAcw|yAlTcxGGAF$>@){Kn%qIR`bc7%)`VSq!G4lyaR z?7lLawP8}heA}$}c#5x79ITyDIUgy#;@qpvo-VLb*={+wP)5U2`ywjT5k*IKSc&&F zB1(-d&fjMvWQM^E_9zS3XAe!f+rS|nP>bC~JtoQ;hT|cpk7`j8Q+1#;R5(qcD%sH1 zS!O|H7P*F_%$c>rld&2UC%!;C(8!u9tWiTX9&V&aOQvb{R-E#tz^HBN%1=j~lrP!h zKKrA}Rv5PmI3rhuOF$tshMm_k5ub+$K;uRh2Vz?$|9)z(mU%r*D=wudFaGl1GVltmS9v!f+8`w_Nwg>sMR-qsm>Zcy#neAzhFz$fbw7hD?%*LG`t1lWEsngG94YAPS2y_}XU&|H zOd6lkwi?W-vA>brW2993sI}b%nGPoyX2Hm?N3ZY>qRfHZ4yw<8l-aWT?WI4sAC1p7 zo1MV5fA{hrHD5Ua4!?r8!9-kj)rAY2XN^%r>5m@Fw=iDt8`5?J*CG6H$kS0Pm$SEu zVJ=UjR)_3iPzEM8U&uXY~Uf zD&}ophSC^r!J45ovTQEYZ$_M_FA!^r5i4@$F`8Ubv5E;=`bj~P;*NmLkT{tnrKr_rG;Zika;?{^` zv-=vYARlxn|3BgJjrG;yk?uovq2xvh8Rp!nu8YV?Tg9pTygF(c$i~%=Ia2AGOF)#~ zH6nx|IjSs)HP91xG0+uvrZ@wB545U^yT%V`Bt3ojkOLzbW(}s6leT?uh1`^!m8MDs zy~koIqy@_iI3T%yM1=4P0+*wS#6TS<(f1 zpA6I{3SP4O*vkJHAk*x-lY>s7U_T3|SS<09I^O6sY<`}yuy)IT`QWEgscXB(4}P}# z@3W$q)ZW%?BbBM6cE3!$FhQFS9OYR)d^0jQMqJ@nxgL*cV z?tW=|kZ>R5Rn8Sf7S^gzlpJ~~1Z>@hRiHY>X7XWvmy5Z7CBug4r;$b(J-n#`+#}`B z9`S++UDjZ~q4?}_sbTAY>b7@=#v@+A*xPzKa^Eu6d0IY=OIlbZDs5Al+X|{~l(|!c z=C2toq?mq`lB!VnAKrqn1?7ImW3H07s@jC+{;Nioru_G#LEBav{g+H;`%?xVxdjd% ztr#$V_dhElwr4N2M!rj~hC(Ly0vjKtgwDsAtty6Z3-?n~$HT!bp~P4>-q$a)O@$WE zL}?Ig9_2M$EEsLuRK^)Ua2WL9&4^u7pI4;{ALnFEZMmxx=^j7=a@a%aNwWGvushsaC%r1XKe#()3s^<*xz!&tf_4CMs zucBM+8OjO&4OR3-*iY@jm_=0wu3kvGr_Cw~^l2_}`Z$<+3ufaM?1$TNCO(M0@Nak~evW73*Vr4gId~8b z!A2Z|I{z+yG=WF42#;deq>VX2fkB%uuqSr!Z;U1%Ms+jZOIxvQsVG4EO zji{NVaRTnd)p!hbTp9OI=T)KVQ&88PfjWO7YK2w|X8m=*TT= znT$-vEJj@@iaN0s^-#8>mhu|s&8UuUN3GobsN?s$`ZLZKQ7d!I?LVG&J3c_I#7WeE z{^9D~c-Pe46E%=9>cah;Ij%k5)r(OBtUwKLGV1)9sE+44mpRjGDRj-y*@{}46lx|{ zpiaEWc{}RDyHGQJ7}dd3&V#4{yx@EVwUWO_?xy)WYJwp?HoSFd)0=`i8jiferWAF- zsi<2~i~4Y^LS1+bY5-Bx0NPN;U+wl^hnmnf)I_YS??j!q8+F}ByY_Sck5JJ2|FYZh zCThkXqdNEsHR5i=GW9;#^~|6;7>PQ*95ujd)BtKxw`wk`<0YtpUhLY}VIRH!Q3^Vt z19icxPzP>Cop=*!fVZJm=s~ytY1Da#Py;xMn%Qqq-;eiD6Ziymy|1ww{ttCtx8bb6 zM%;^nI_{6^AO{ot4JgHR)OVeix$rm0b7}f|?pC4RnyEM!mm(igvkNtl$59==gc`sr zxBy>64In4az5iZbW~3vqk{wm3XQBalWla(n;a1d4-*Nj-pa$?Is^ebynGZ`YuBSc? zwGz9LyJ#Lq4mGc#9?DPi)0w5s;&Y^>8iZPb0@TWkN3G0s)QIPx2Cx7(<4V*$K8|`O zKERRq8S4DOg_&EJkGh4UaUxE^u^6N&=-a;+wPeqsM*KSRc{cB0F`jbmxg#?BN8vu& zC!q%ZSFFX8n1$nuGRI9u4R{{vSz7MuYjHaDbd-XYVlQe2M^PQWiW>3zs2QHZ9{4rt zmV}t*Y|O=VxB=C{FHsYE71i-^)QW!S>i@*i)I-dQfu>Cv1)Vq+=iwCGhBuAGOMH!U8=gshC-%ZUsFm7}y3P?)2ggtk@gJQhQ0IM#J@LPoP5-7xX{MvT zsE!6ilL@M;)kvZ9?6e+c1m|U|J(OKtU%w z=XSj4d;@iXcTvZEi0be&)I<6uY9MEnW!ld~bTGeHnphzYf#TbOBw60 zrQ1Ypp;qJ=>Oya$R^}r-3s1WJ|3RJCqdarHFlr)wQ3Dz3 z>Q&{ezb;fmg9b7W)zNBHdlTxy8=YHR`>n3N8+G1es3ks(8qgcgw@@9whnm<4)JlGg zI`6AAg|3l~$;>Q_I&h$?=b#QOKrPug)bX>Ob*Kw2MGasL_QnKi;8&xrcQfi1--0^- zZdXs=PeCKzhq?t%VhFbpKL2J9X(Zb8R%mM_dKJf$*<=HmMm(bJ1(NJ4W&U)lIF-yN z-BkI0OPf2WL|ubEEIY}?WEJ5yc5S!wdpFrgZXo)GUq>|XLZVI2OB>NFFCp44$Y8F; z$)t~~A93pY)3yD8-^X0zv$&reBzoB9k&$FHd4yDw^T@448w+N(kQ(wNxr|&&v|Uc} zNj-U#{FD@vhl#fCu7C4GDvP?B`2RaDBUh89Bp~;Z!{poTaaVW-V`K+ePi`VB$vQHY z=&#;Sh@O!q5Sc_y-yYEVUqQ=qa*f-gr}#NC#MMt{9Fndj9kbtRPR3v&nAq?G~nRGpQg=MDKKeau?AyjFgfp@-*RdVoJyX zqOCJS*Y5&;x08!p+mBJ_cWvkJ+u_R1&bVFMZ-?#Kzc5@JPk8l_wjh>>m)P?D(+1Z! z#abG?wn)@BGa4GaxPO@!3;b4ls{duSZNN%fGVm>X{-9O%@SuA-*AK1;**!z{+towY z+UYs-ZBgzJyDm3pK&-yWTkdZR%(6&_ZIdG6rFC9oBI!ligG6g2h}C;Zzaf_N>w{Fe>AK$XrbxUwm1pl7Hm@^( z_&Xt6>_z%S>NWh7ksZFR&RdYRp(Rn@+_@z$6tY|MXP@CW2Ayx@ZwqB5W6`Fdb4}r( zP+|7sMa#=-lRo_<;$<@cQ&CAM+ph07+Kw3+ zElhc_l-J=W+gc)#AQhCG;;8S(y+pjhPp0adlCj31#Qt{V;&7^c1B)MvN4y|m%|A`eI-Nfy(LTR%2A)&9iwBmy7WNj7o~GT_M-CV?XWS8HoIbi{j_45T~e7pd{JA} zZ;eEn1D|`)oC?gMwiLa_&BY17*|+;Ei|oHDe_@YS<<`uK#T(k%, 2013 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: LANGUAGE \n" -"Language: nl\n" +"Language-Team: Dutch (http://www.transifex.com/projects/p/feincms/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Language: nl\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "template" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "volgorde" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "taal" @@ -34,7 +35,7 @@ msgstr "taal" msgid "All" msgstr "Alle" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Ouder" @@ -43,50 +44,50 @@ msgstr "Ouder" msgid "Category" msgstr "Categorie" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "%s veranderen" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "titel" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s is verplaatst." -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "Begreep verplaats instructie niet" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "acties" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Item echt verwijderen?" +msgstr "%s items succesvol verwijderd." -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "" +msgstr "Geselecteerde %(verbose_name_plural)s verwijderen" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "applicatie content" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "applicatie contents" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "applicatie" @@ -143,65 +144,45 @@ msgstr "bestand" msgid "files" msgstr "bestanden" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "afbeelding" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" -msgstr "" +msgstr "alternatieve tekst" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" -msgstr "" +msgstr "Omschrijving van de afbeelding" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "onderschrift" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "afbeeldingen" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "positie" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" -msgstr "" +msgstr "formaat" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(geen onderschrift)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "media-bestand" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "media-bestanden" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "blok" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "links" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "rechts" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "type" @@ -226,19 +207,17 @@ msgstr "Negeer de HTML validatie waarschuwingen" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"HTML validatie leverde %(count)d waarschuwingen op. Kijk alsjeblieft de " -"bijgewerkte content na voordat je verder gaat: %(messages)s" +msgstr "HTML validatie leverde %(count)d waarschuwingen op. Kijk alsjeblieft de bijgewerkte content na voordat je verder gaat: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "tekst" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "opgemaakte tekst" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "opgemaakte teksten" @@ -246,9 +225,7 @@ msgstr "opgemaakte teksten" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"Het RSS veld wordt meerdere malen per dag geactualiseerd. Een verandering in " -"de titel zal pas op de pagina verschijnen na de volgende update." +msgstr "Het RSS veld wordt meerdere malen per dag geactualiseerd. Een verandering in de titel zal pas op de pagina verschijnen na de volgende update." #: content/rss/models.py:22 msgid "link" @@ -282,27 +259,27 @@ msgstr "sectie" msgid "sections" msgstr "secties" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "plat" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "titel rij" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "title rij en kolom" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tabel" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tabellen" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "data" @@ -314,29 +291,27 @@ msgstr "template content" msgid "template contents" msgstr "template contents" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "video link" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Dit moet een link naar een youtube of vimeo video zijn. Bijvoorbeeld: http://" -"www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Dit moet een link naar een youtube of vimeo video zijn. Bijvoorbeeld: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "videos" #: contrib/tagging.py:117 msgid "Tagging" -msgstr "" +msgstr "Taggen" #: module/blog/models.py:28 msgid "published" @@ -351,9 +326,9 @@ msgid "published on" msgstr "gepubliceerd op" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Wordt automatisch eenmalig ingesteld zodra `gepubliceerd` aangevinkt is." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Wordt automatisch eenmalig ingesteld zodra `gepubliceerd` aangevinkt is." #: module/blog/models.py:39 msgid "entry" @@ -368,12 +343,12 @@ msgid "tags" msgstr "tags" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "vertaling van" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Laat dit veld leeg voor bijdragen in de hoofd-taal." @@ -390,27 +365,27 @@ msgstr "gemaakt op" msgid "modification date" msgstr "laatst gewijzigd op" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "content types" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "gepubliceerd op" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "gepubliceerd tot" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Leeglaten als het item voor altijd actief moet blijven." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "zichtbaar van - tot" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Datum-gebaseerde publicering" @@ -438,98 +413,98 @@ msgstr "meta beschrijving" msgid "This will be prepended to the default description." msgstr "Deze beschrijving wordt voor in de standaard beschrijving ingevoegd." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Zoekmachine optimalisatie" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Wijzig vertaling" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Maak vertaling" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "vertalingen" #: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" -msgstr "" +msgstr "Dit zou een oneindige lus maken in de hiërarchie" #: module/medialibrary/forms.py:64 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "" +msgstr "Kan niet overschrijven met ander bestandstype (poging tot overschrijven van %(old_ext)s met %(new_ext)s)" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(count)d media file succesvol toegevoegd aan %(category)s" +msgstr[1] "%(count)d media files succesvol toegevoegd aan %(category)s" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" -msgstr "" +msgstr "Voeg geselecteerde media files toe aan categorie" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" -msgstr "" +msgstr "ZIP-bestand geexporteerd als %s" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" -msgstr "" +msgstr "ZIP-bestand export mislukt: %s" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" -msgstr "" +msgstr "Exporteer geselecteerde mediabestanden als ZIP-bestand" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Voorbeeld" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "bestandsgrootte" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "gemaakt" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "bestandstype" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "bestandsinformatie" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" -msgstr "" +msgstr "%d bestanden geïmporteerd" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" -msgstr "" +msgstr "Importeren van ZIP-bestand mislukt: %s" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" -msgstr "" +msgstr "Geen inputbestand opgegeven" #: module/medialibrary/models.py:43 msgid "parent" msgstr "ouder" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -575,7 +550,7 @@ msgstr "Opgemaakte Tekst" #: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "" +msgstr "Zip-archief" #: module/medialibrary/models.py:210 msgid "Microsoft Word" @@ -593,23 +568,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binaire data" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "omschrijving" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "Mediabestand-vertaling" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "Mediabestand-vertalingen" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Deze URL is al in gebruik door een actieve pagina." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Deze URL is al in gebruik door een andere actieve pagina." @@ -617,76 +592,78 @@ msgstr "Deze URL is al in gebruik door een andere actieve pagina." msgid "Other options" msgstr "Overige opties" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "in navigatie" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Voeg subpagina toe" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Op de website bekijken" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." -msgstr "" +msgstr "De inhoud van de originele vertaling is gekopieerd naar de aangemaakte pagina." -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" -msgstr "" +msgstr "Je hebt niet de juiste rechten om dit object aan te passen" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "geërfd" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "uitbreidingen" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "is actief" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "actief" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "overschrijf URL" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Overschrijft de URL. Als het een lokale URL betreft moet er aan aan " -"weerszijden een / staan. Dit veld heeft betrekking op zowel de navigatie " -"als de URLs van subpagina's." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Overschrijft de URL. Als het een lokale URL betreft moet er aan aan weerszijden een / staan. Dit veld heeft betrekking op zowel de navigatie als de URLs van subpagina's." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "doorsturen naar" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "Eindpunt (URL) voor automatisch doorsturen." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "URL uit cache" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "pagina" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "pagina's" @@ -696,41 +673,38 @@ msgstr "samenvatting" #: module/page/extensions/excerpt.py:10 msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" -"Voeg een korte samenvatting toe die de inhoud van deze pagina beschrijft." +msgstr "Voeg een korte samenvatting toe die de inhoud van deze pagina beschrijft." #: module/page/extensions/excerpt.py:12 msgid "Excerpt" msgstr "Samenvatting" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "navigatie-uitbreiding" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Kies de module die subpagina's voor deze pagina definieert als je de " -"navigatie wilt uitbreiden." +msgstr "Kies de module die subpagina's voor deze pagina definieert als je de navigatie wilt uitbreiden." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "Navigatie-uitbreiding" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Selecteer pagina's die beschouwd moet worden als gerelateerd aan deze." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Gerelateerde pagina's" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Site" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" @@ -738,8 +712,7 @@ msgstr "verbonden pagina" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "" -"Als dit ingesteld is, dan wordt de inhoud geleverd door de aangegeven pagina." +msgstr "Als dit ingesteld is, dan wordt de inhoud geleverd door de aangegeven pagina." #: module/page/extensions/titles.py:13 msgid "content title" @@ -747,8 +720,7 @@ msgstr "content titel" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" -"De eerste regel is de hoofd-titel, de overige regels vormen de ondertitel." +msgstr "De eerste regel is de hoofd-titel, de overige regels vormen de ondertitel." #: module/page/extensions/titles.py:15 msgid "page title" @@ -767,10 +739,6 @@ msgstr "Titels" msgid " By %(filter_title)s " msgstr " Op %(filter_title)s" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Zoeken" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Item echt verwijderen?" @@ -789,9 +757,7 @@ msgstr "Kan item niet verwijderen" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Kan item niet verwijderen, omdat het de ouder is van een of meerdere sub-" -"items." +msgstr "Kan item niet verwijderen, omdat het de ouder is van een of meerdere sub-items." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -802,14 +768,12 @@ msgid "Really change template?
All changes are saved." msgstr "Template echt veranderen?
Alle wijzigingen zijn opgeslagen." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." -msgstr "" -"Template echt veranderen?
Alle wijzigingen zijn opgeslagen en de " -"inhoud van %(source_regions)sis verplaatst naar " -"%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." +msgstr "Template echt veranderen?
Alle wijzigingen zijn opgeslagen en de inhoud van %%(source_regions)sis verplaatst naar %%(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -831,30 +795,32 @@ msgstr "Voor" msgid "Insert new:" msgstr "Voeg in:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Leeg gebied" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"Inhoud van de ouder-pagina wordt automatisch geërfd. Voeg zelf inhoud toe om " -"dit te veranderen." +msgstr "Inhoud van de ouder-pagina wordt automatisch geërfd. Voeg zelf inhoud toe om dit te veranderen." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Nieuw item toevoegen" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "" +msgstr "Voeg nog een %(verbose_name)s toe" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" -msgstr "" +msgstr "Verwijder" #: templates/admin/feincms/fe_editor.html:40 msgid "Save" @@ -894,24 +860,24 @@ msgstr "Startpagina" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Herstel verwijderd %(verbose_name)s" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Druk op de opslaan-knop om deze versie van het object te herstellen." #: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "" +msgstr "Geschiedenis" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Herstel %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Druk op de save-knop om deze versie van het object te herstellen." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -935,28 +901,28 @@ msgstr "Op de website wijzigen" #: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "" +msgstr "Voeg toe" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "" +msgstr "Voeg mediabestanden toe aan categorie" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "" +msgstr "Selecteer categorie om toe te passen:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" +msgstr "De volgende mediabestanden worden toegevoegd aan de geselecteerde categorie:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "" +msgstr "Voeg toe aan categorie" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "Annuleer" #: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" @@ -964,7 +930,7 @@ msgstr "Opload meerdere bestanden tegelijk (zip-bestand):" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "" +msgstr "Overschijven" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" @@ -979,14 +945,9 @@ msgstr "%(comment_count)s reacties" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s zei op %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s zei op %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -1003,6 +964,3 @@ msgstr "Verzenden" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Bedankt!" - -#~ msgid "Symlinked page" -#~ msgstr "Verbonden pagina" diff --git a/feincms/locale/pl/LC_MESSAGES/django.mo b/feincms/locale/pl/LC_MESSAGES/django.mo index 2caf743d4a2daf071deee0064937ed940a45b482..ef7824d2165de21ad202163fdfb753cacaa92d66 100644 GIT binary patch delta 4161 zcmYk@jfFfuNt0Dyr3k#wIX`%)-R6$IFHO5FcaDi3c++9Ejar34o zHi~AkF_k7Uv1+QBq|!fD_S zpZSv2cucv?m<*hPP3S=#zYjH#qnL{)F@^J+&)MM5Tw|4t2@F$(q@gO!LY*iZ<1rt{ zqT9CT;Y`{KP~Wdd_2b|a+=O%S1yrFYaU!0rjQPL(NDd>U(Xd6ZW9`Ifgp!15|&%MIHZV4C#RLY-nVcQ5AoIDkz1cwLjN7 z$6AEyuoTtNV!OWzRZtBs!qs>e?n4ir#s>Ts7ULrmng0?tb}=97=x3-Y{1A15k8l~D z#R|;f0%~f#s1voJj_b1f`;orQbI2iP2z4*~5OqKQ3N=$B*0YnCf1T(eJ2W*{Q61|j zwG*uwsF}(^eeSmV=b>h(5>;50ZP!`XV&tAc9p_lv?EbD08>;MaRAt*x9S)#QIB0#v zdIZ(saqGLN8Tcux;M1t%My!89_4^rWpjS}+{||NEQ0(OB#(2~SGEq-M4ywaaSi<;H`kfsUXa z(~HxXe|7Y4cBp_vhM|IPL!B_gwq2;obFGD_0?TZBJ?h?QM$K3Nm*7s+D|ZA{&;``_ zuH$qZo6Y=d3iGq0BPd6;Yf&@dMUAk7N z>xvebi0WrXhz%Vu2Q?+7sF|oj6|l;>231%+>hn%ihnrCaY{7-N1NCbCHJ0HGT#NG= z?reO~`V&+?q0iY+M^}({g83&d!|^lt!NEGzNCr{gJAgXyFskskQP=)G)Brw0^>e{~ z{vT^Rccf-46?G}HkmEwe&4xx$iMlqmwq1`p!A5Hr>RN_SkJW&65LMXAs2O|Jwhy5S zJ!acKLLK*G)PPPz4Do#04?adcKIc$xzAsP(+(eyVTu$_wO|WL7PBGF zQ8Q7E@z{v!--nuseoW^4W;+{tzQd@gIg0A&1JsGnU_Aa2RoGcn2Y*A&+%;4oF|(qd zC!*RJ)@i7Lk1Om4t5EmC!>9vVP#yGP0zPTojw*PU zbw9?@K7#uGG3#;EjJ<2yr%*HeVJ`C@!$vlFm~1D@h?XA^JprT3A~rS>z2RC$cj9-* z5pq9yo(z#1q8UvfZxSuD$+yY()UeCzy8f%lUb4aN)YNO4A0@ILWIgYewl>{Fqu5U# zAsu7~IZB=;TD}p*?8E^QOTu>F0?dDnm9FiBM2jwiE{U%5ouq+iX$ntIP7mq!Tpno~ zQ;x5aedGaBMDoZ=vXt=HM3yqvb4gdU8Ch%CcM*Ol%zBbYc9TBhCt4Pg$H*MAjg;zb zaqCh{V=>V!c#L$D0I4P~kvgJf6xvRLy zGy1)vyURV{%UPMBYHu*u;`0Vv%bh^bX>aLh?Q>PMZCt2xwK%?@yP@Ttq!r%w<}Pou zQ}B@EZ7X-xcC`8eEw0fDdwP1@LBF>>;A?U=M+)uqcWiJPf`P)$uWD_zT@-e<7Um~a zS5+@5Snc=&;WblMrHpo8?&@p}ADPk^vml%@wQ9Iw>ZQ2kjUAdoufMO?9bTH9mr&#F z^ac9DZP`B$m$|Bk-*i148}`inT}n@{|J3m5_uCn5Z#Xt*=kQ?8OEFcy7BNq~4ASPtPBOyS5kTeJh5(sI9A}-73(ImTZvuQ{` zRz*T9&-PY|B37xirC711XvcO&E23kWc4*5uNQ-D|+c6!BnNDe?jMM+Ods2FbZ-3{W zd+&MON4Q*jaCP+k^rXiP+lyo}c`DhMYbuZ8hwW0DF?Zm5I2NyA4kp}gOe*GLBF;fw zUxJ)s>TweKQRhWb*X=|8nIH2*S5fl|3Toi(c!fES!`c6h^^)}}rc?hHti;bS1vUH=JcLYhr3{TmMjjc_q?%&bIBej{oiO~^=15Y%ZKwhEp$6ol zI(`zh0>@DUJB8}t4C?v;)ODYu+8ITquFpW7?_g9jnPm^mMvZhnY9Mu}XYZt2F zUQ~m7P%}SZkH3T(;48QcU&FgFVZ1S3EJQ!vKc4k3rtl^ebMRlN2J^W=TEb#fN2OSe zRk#TEqn7rUsE*!6UH87N|1;938AO^i$vg;p7Bcx!yIvfLB_7saOISgLT!ree9%By? zs)LZ-@3!tnEum|VAG7r*P%GAt8sJau{+rf!Py_fis@;oGTlj-L@DXZc1E_}niR$Qv zHEBY8KMmE;MC(-43gn;$o{ze2fps}*g0-j#HlW&%`fZ^Z)p5IZ8)^o-P;bRSRKw38 z53qRw)xhhh*Y_Oi`gc$rT|{+s1$EwlJ$?-}@Egd0S^tUgiV>&_N26xqL3KO@bq@WN@imOyD^!CQ zQRn?0HP8=G1N<1ZA~)>uR9+ojHx@O338?m_p$1-rYG*MH)B9gRK^Ih^M!E{sVFRk+ zP55*I4rgYjV7-i*@kgi`{{wjwxtDy*z=N8|!6~diW%C?A zh4=<)#)GK$H<4khp$Vt~rn3I} z77tRP5hY~BJM`c*_Gh3*UX5DHO{f_KQ7f?>)$t>!Telb0(P3PK$58{lin{J&)C8}i zCXy0$;v-5!HI#>H*o(Tb6txl+s1;~H9ly^SKn<)7b^Jlpz1@xK;3R55r*SF%4E4pm ziKQ5w%``VqXvSH1*7|o;gBjD~4NXJ7LFP`Z#&RsjKGe+4p*s96>bgs)34DNB!2#4n zG&;329yvd1@+s&NR`IdLA{v z3#b)*H?|+;3q?UA{*yi7Z>S3gQ8T-4_Y-sCuTKiz*>RoXcelR zwWwRQ+17WU{{EP53Q2gt>Y`rDBdC=)g_`-xsQ3L1)XH2&HFym*06p?aFdQ|&QK;)P zP}k?622^B^mta&CRrWv)YDVi&E3(P%2T)5ILOyaPiki_8TYmy|i_W0#?RnGy{)ox= zDeASmj{5(_nA~`MzW)EE0eGp9rKl5^pf0=@^}1|E4d?-D4{D|l+xs^=yyS~S+h)Q?%J{Uy_MG0GO%%$A-e@g& zBYBY&5^WC>t!Fc7Aa|25kbB9KWH(tw!X%%3mHdd*5N&$eX2nYJ|FGGjd4@tK{l`AC zs;nlu0lG=O@c+Ln^}DzI&g6Z>NH*|OL{9wB#WNAJ!u z!e1}*L$Z?$Z8ItCvOACBW8_OD+171E?!DPhx^3NBOeA*_ecGNSIb>+dqj1XZ^k9^S z!L-_ncKizYI?=$sOZeo)wkP;aA`g?fu^RpaSs%iqWE5FIzDKm_J^TM{3Omn}X=E{Z zK;3Mku#X%hE(wxsqV2vovEP;a4!8Sj@CZpIbtFQD5p4xz9yvrRh_)8;9a2e($gPcO z9%iqUY`9e$dvE5jUu)~`w{F3Oq=|fuw2^x9IMLrq57G8C$s*q*PZ4b=$O;l7DdaRU zx*ysm$BF&!<@YwSgnXMgWIYfCubk8~FHuNe2xu;eXmA%Cm;_8qUghdjZ= zKx3r;re|(Ka=4|bInqCSVnRaB$Tj!W7c374xI7drsPshwWlnLCx459Fw7@&x@s^f( zOWYk9lY-RDFYwNDib~6h=j9i%jjZu?Mhfb~zF=pYFA@ruIqjY8fnaY>tFvgRv@}#) z*wI$bsllc$UsIray2@EpQ?s2{>n)MiSClD>27n@*`#&7U9E1OvnE?>u{AWb6g~dlV2{7q z=?M1*T3Z6)P`B^gqy62^uAwFQZ2Irq_p, 2013 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" -"Last-Translator: msmenzyk \n" -"Language-Team: LANGUAGE \n" -"Language: pl\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" +"Last-Translator: Matthias Kestenholz \n" +"Language-Team: Polish (http://www.transifex.com/projects/p/feincms/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2)\n" +"Language: pl\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "szablon" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "sortowanie" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "język" @@ -35,7 +35,7 @@ msgstr "język" msgid "All" msgstr "wszystko" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Rodzic" @@ -44,50 +44,50 @@ msgstr "Rodzic" msgid "Category" msgstr "Kategoria" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Zmień %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "tytuł" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s został przesunięty" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "Instrukcja przesunięcia nie jest zrozumiała." -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "akcje" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Usunąć?" +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "zawartość aplikacji" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "application content" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplikacja" @@ -144,65 +144,45 @@ msgstr "plik" msgid "files" msgstr "pliki" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "zdjęcie" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "zdjęcia" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "pozycja" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(brak napisu)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "plik media" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "pliki media" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "block" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "lewa" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "prawa" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "typ" @@ -229,15 +209,15 @@ msgid "" "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "tekst" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "Obszar tekstowy (WYSIWYG)" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "Obszary tekstowe (WYSIWYG)" @@ -279,27 +259,27 @@ msgstr "sekcja" msgid "sections" msgstr "sekcje" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "zwyczajny" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "tytuł" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tablica" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tablice" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "data" @@ -311,23 +291,21 @@ msgstr "tekst szablonu" msgid "template contents" msgstr "teksty szablonów" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "link video" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Umieść link do youtube.com lub vimeo.com, np. http://www.youtube.com/watch?" -"v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Umieść link do youtube.com lub vimeo.com, np. http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "video" @@ -348,9 +326,9 @@ msgid "published on" msgstr "opublikowany na" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Zostanie automatycznie ustawione po kliknięciu \"opublikowany\" powyżej" +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Zostanie automatycznie ustawione po kliknięciu \"opublikowany\" powyżej" #: module/blog/models.py:39 msgid "entry" @@ -365,12 +343,12 @@ msgid "tags" msgstr "tagi" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "tłumaczenie" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "" @@ -387,33 +365,33 @@ msgstr "data utworzenia" msgid "modification date" msgstr "data modyfikacji" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "typ treści" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "data publikacji" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "końcowa data publikacji" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Pozostaw puste jeśli nie chcesz określać końcowej daty publikacji" -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "widoczne od - do" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Określanie okresu publikacji" #: module/extensions/featured.py:9 msgid "featured" -msgstr "" +msgstr "wyróżniony" #: module/extensions/featured.py:14 msgid "Featured" @@ -435,19 +413,19 @@ msgstr "tagi meta - description" msgid "This will be prepended to the default description." msgstr "Zostanie dołączone z przodu listy tagów" -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Pola SEO " -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Edytuj tłumaczenie" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Stwórz tłumaczenie" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "tłumaczenia" @@ -462,7 +440,7 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." @@ -470,56 +448,56 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "Dodaj zaznaczone pliki do kategorii" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Podgląd" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "rozmiar pliku" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "utworzony" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "typ pliku" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "informacje o pliku" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "zaimportowano %d plików" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "Brak wybranego pliku " @@ -527,7 +505,7 @@ msgstr "Brak wybranego pliku " msgid "parent" msgstr "rodzic" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug (wyświetlany adres)" @@ -591,23 +569,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binarny" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "opis" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "ten URL jest już używany przez aktywną stronę." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "ten URL jest już używany przez inną aktywną stronę." @@ -615,73 +593,78 @@ msgstr "ten URL jest już używany przez inną aktywną stronę." msgid "Other options" msgstr "Pozostałe opcje" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "W menu" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Dodaj podstronę" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Zobacz podgląd strony" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "Nie masz wystarczających uprawnień aby edytować ten element" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "dziedziczone" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "rozszerzenia" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "czy jest aktywne" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "aktywny" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "nadpisz URL" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." msgstr "" -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "przekieruj do" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL do automatycznych przekierowań" +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "strona" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "strony" @@ -697,26 +680,26 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "" -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Powiązane strony" @@ -757,10 +740,6 @@ msgstr "Tytuły" msgid " By %(filter_title)s " msgstr "Po %(filter_title)s " -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Szukaj" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Usunąć?" @@ -779,9 +758,7 @@ msgstr "Brak możliwości usunięcia elementu" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Element nie może zostać usunięty ponieważ zawiera przynajmniej jeden element " -"podrzędny. Usuń wpierw elementy podrzędne." +msgstr "Element nie może zostać usunięty ponieważ zawiera przynajmniej jeden element podrzędny. Usuń wpierw elementy podrzędne." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -792,14 +769,12 @@ msgid "Really change template?
All changes are saved." msgstr "Zmienić szablon?
Wszystkie zmiany zostały zachowane." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Zmienić szablon?
Wszystkie zmiany zostały zachowane, treść z " -"%(source_regions)s została przeniesiona do " -"%(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -821,19 +796,21 @@ msgstr "Przed" msgid "Insert new:" msgstr "Wstaw nowy:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Pusty region" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"Treść ze strony nadrzędnej został automatycznie odziedziczony. Wstaw treść " -"aby nadpisać odziedziczoną wartość." +msgstr "Treść ze strony nadrzędnej został automatycznie odziedziczony. Wstaw treść aby nadpisać odziedziczoną wartość." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Dodaj nowy element" @@ -954,7 +931,7 @@ msgstr "" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "" +msgstr "Napisz" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" @@ -969,14 +946,13 @@ msgstr "" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " msgstr "" #: templates/content/comments/default.html:28 msgid "No comments." -msgstr "" +msgstr "Brak komentarzy." #: templates/content/comments/default.html:36 msgid "Post Comment" @@ -989,6 +965,3 @@ msgstr "Wyślij" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Dziękuję!" - -#~ msgid "Symlinked page" -#~ msgstr "Dowiazana strona" diff --git a/feincms/locale/pt/LC_MESSAGES/django.mo b/feincms/locale/pt/LC_MESSAGES/django.mo index 8803694505c246c20213bb9cf6f8c87c69d4050b..2c8c9dd3347bf1b5bafdd21694686b3fabeccc40 100644 GIT binary patch delta 5022 zcmYk<3w({|0mt#@kRk~U(GWx(A~(4w5=2!fB@IpHHc>W591@o#b52AtM@!16rbMQj zDpf7(v|F9(&D>TqmtkzmwDqZerrlOPow4d%X21V=pY*f$|_Vg#nz_IzY) zGYE%aDSEI8+u%(MN3AA`@l6B;Ew(Fm!epF*gHav5hWs<{^TM^}6ei+dQ7eh$qV^bz ztuX~7F&mR`5NcpAY5`TKh1Oy?OZLWwdAV)*dDc# zB2;@R4#g>`E#HD#z-83RucG?-1~pO5TI1z)W&hn2ifB+rvrrSLLk&=mOx8S$>R=mc zhu%c~nIJFpX-;B3{tchN9z1D!-y+m?OKp9XwE;EW`flvM26~x>dAI{L^KLx4>L4Cf zPsVYWg<4@f4#8tsk8QgflZNY15AA-;z-w5J?gx#@!R45X?_vsm6`-IA#Po3PZ5(Q5 zy>J9(;zL-6TJhVc9XW+Of96Znvv3zR(QvoZUkB7Zk42qNLT!02>X{gUJYFU+nSw6# zp*}{7Q1|Q^YXfRRFQ9JCtEl$}ZGDgRC~B+Eq0V1Iz5nm1oxF*f$Q@g6(=*f_FzqPl zsg6cn7;AOg_GDYnKus_oHNhdMjvqq}Tw*P=mZSQei`rqItuM6orPxlN{}mL}L6dbe zYJgv$R=x{0(01*X=-c{FXg`81=<;!nR*TE%Z97|GOB_j3fAV zQ9~zGJsvecChCHG)C3Drx2PC3;8@fIC);)p>Y=MdO>_aOpCuSt2)C5l8U_6Iz?3`o_A8FGc({KXnW3>zi;Re(*aTc|ZE7pIZ z`u!GL;e*M}`Gf!kZAmKXA?k}-;V9c)hI}WPX*d*@;9@+8n&87J&ihBAwsbs3;|$b9 zpTv>4!JhxjwqHYie*~iXI4em&ZSfe?iagjFYf&Bk7>D5VsAuGiJ%16k(l0O^ui$e0 z#-3l4>a;II{V1(L=5972I}tF4Dd=Nz0=3eQQQvqsaUk|(pLJmk>RDKdnrIX9yJWVZ zI^2tz_!rm{Z=tS>OXoquG;E6pFf<+(>+}CHg$Pb0WjHI%!D8yeu>{wm&R@bdc*Xi} zd;Y)Zrv33u=P#jZ)Bx*ITf7yulkcH^tPY_1yP$T)HP zM0Ir5`YDD{zl>4%57hf^;Tm-DOQiQVpl;Cy)GgYCqi{P0w9*?CO0h7IaScogok4I4F2laKH`fB8pXx>2W&}q~}E?^{H!ZN&yg*bx0Qh5H%$~^X;A3(Fq zHk?M?quZ#C+T=SOb-)hPV^JOULEZa&)RvamdL?SbPouVY6>7yzsD3x2K4m*m*B{Df z|MiAXX?Os?L_O_yQ0-AHUv@!FARe`qd8mmDL=7|owc;_>GTS~CwUF7UiTSOI?fK;a z3hJl<^~Q}DdaAJ_^}X00PopOCIjW;8r~z--`fa?QddvRK`DoPnuGXH|iFz`spTVeS zCQw8{D=))dScSTmYcU3Qqb6`1HK9*z`#(_+U#kJmgd{2w(av#?_XluSE6>N0ky@ipq`NrQ2iW0 z?cfpYf`36R;5tU?^Y7woP6M|?bsUWvFb>smJgTF9s1*%H7rMz1a)$hYc*$_WqhO|! zo#ZUpOqvfrg?GsbqDcj+dHEsvCCMb3fL5&^8+|k<5FNiIvqL5RGQv}&v#tLOE6855 z+qR9zACW|&)ovv^^i1e@#KHOf|2>tTl02dvSwL^`q5%_$Vx}l~-^i z`3dPnwh-Oc(4p1-hSZQpiGBxke9s~Dz#ON%hs2Rz6Ft4plGliiKBODbLwA_yC~`3S z@Q-9FnMHOG9Zxwp>wk{Qo3^3c%BRP?PwL5^$Qm+-yhn}_9ghSuan3K(u+J#bd-^Eki% zq6$YUIZu8?UM1;7$0!H04s*2rVYcB3>tZ}alF7qFUpnuQFw%T%w1wZ{I8sY`+qT!O z8!(#mCC}KlY+OyYk%45b?*D$GKOPSf9iz!u(xeKGW_#ARldp@-UXrA*37G( zRT7(c+(BA7NX+VwwEy&!@B delta 5259 zcmZA534Bdg0>|+af{55+iH1&}h}e=yh#-{Mi`ZiulqY#2B=7O^qQ)|B6k{n>Qf;YH z9gI;+_0`g;rI^+jYqfN-^iyi4V=#0^M`v34`@egb`ON+FpYJ*6-gmZp?|W^}PCGC? zcsVw5rQx_t8jzSu#Qf0F>1oIQMX`)t*^)6V>IlhpcR}!ZjZTy+KD^379XG{xR#4`-DYfu zyHG2+W!vv!SL)@Mjkdf8Y5|K;D_?=?=T+21H^#I78t@AmTzCsLKy{uFO`rj4fab{J zOggHA-l!cKV$Y92K5E7yb1*Y76JNwpcpPQ6Z{r?;REc5yYz93^%{h_m!qv7)Wp1~TQ(DQ{UTdmZe54k`fc|79;ZEM z4pPvTovr?11XHGim~TP!kw}x_+EJ??LU@6x70|+4^kM=jNjNU4lVf zu%3dxxi;Gq@1jVuO}6AYksXg)^b%c#$-K~4A#)XKJ^`aOhNz!{9hOIQxC zpgwmkk^R?<|3-rb{th+3k2p1gThZA0(U_CubbJ+g^UOWey{y-S2Mg0sw{RG0BKg=E zz39U2$X9_mjmdZu_147)o3b4gQc({{5o%_0t&30tEJICjmu=sNQPdBkCUP9L(yO-p zHu9xszQ?XurTG2hMgfT6g{%T_v>P=A3P$BAkDYDR@nN6WG4RdiGF0~iL(!1K@QNLn|$YM+e zYA42^wmcuTQa|b&@p4}Z0h{Xm&!wQ5&qlsW%yQHRLs*7K zFb0RG+5xdIbw5Vq0o2YNv+Wmg0QIIVo%7Q%iuzpZ5*$E%CAt{jT%*AAW-6vR1GGSG zaeLHO4M6>>4Mz<))wa(@uk)ssGsMLFb|{o*C*|m7sFd`osGdrPRyrJ9T%f6 zT#ZX{J?aB3`Gv~Bwy1}*2z6`xn1i!WJ8}#MVx88;JckpIF3h*s78B_t8%JXRU&~&s`cKqE?guGopc>pT&8RMFpaj&6Q>+=by#s1RJu&=jSclv5V^RG~LR~iv>tPUU z;VW1Jx1uH*+)qIr9Yqaz+SbowHR_jb{iZ#C*ZKq2<$U?}&Oq^~4jZAKr4-Z-Jc$W7 z7iRfT zdm?Hg$*BI?pcdBIp6`y;^#12i(AJN#C&r^bFv+$DP&+gewdKoD&&(#&KwDAw^c{Q* zKR_+yOVm!?L=F5ss^9yl@uK*;465Vm6x2~8)XG|51nOPxLyF07NjWl}xJhU7{|9g7 zqvJP}x{~FDN9ED6htkKSvD2dUJI6%p=MNi@d4#{g)U-u^I955B#dw%ZCNs(N#7~Y9 z9f=O%ziVu{8GcB#OM3kd>i++n!fMir=*fJK=+GATBAZAGd7tRWChLi&{w#T&j3Rr9 zj^8_k|E{p*%lI-GK@vy~IYh#pjKkfkaEx?#^miMjG304-nw%nhd4-St{B3Q^o2}v^ zIZmdLHwe$E=}&f&b7Ud;guF zT$E;)ZbgYu+=v~-%xFzikW$r9os;q~j)hznQvZvdP^s@Zxae9M*};-&B=*+JTq z*T@BuN^~TX`eZO^K@JcdXGlZx1nEL%lkonp!}+Rk)FqQh8fi|3li!gf5=Huvhez(i z0+x~!#6y~r4n)TbWL~)B{25@&(Rh}G?|*Y(5B0An78^a}I zeuXngH(PIl>13|0H^N=yBa(01Linyzo@CBbh#{Xk4dL&66<;EANG(-3eB=nJO8!7} z>?2jeCH_YhW{}6pNz#cdB@d6aWht?zVw!q=t~~dYK%vjuEcEZ#gOx&W$NM7^-2MVj zz%_Jmj%$L??{b$0e8uiSVV=wH$uIPK@&YBPp@as5A}fq9^5snq`Ca`Z%6ldRLI)Zy zji}%+ESMMw^=VW$A~Aa4fZUXBeh;7Zc~iQ(1D-5btF-i1DQWFe(lcG@?XuF_mTgU} zAEYHSrFELCReDyN^cHCx(K+stKuWIP?JX&C2Ymi4*RUho(ABfBpwv_7KN50voHoHJ z`?3p)-GxP|dA{OKe9l`?>Mro4, 2012. +# Vítor Figueiró , 2012 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-30 21:51+0000\n" -"Last-Translator: Vítor Figueiró \n" -"Language-Team: LANGUAGE \n" -"Language: pt\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" +"Last-Translator: Matthias Kestenholz \n" +"Language-Team: Portuguese (http://www.transifex.com/projects/p/feincms/language/pt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Language: pt\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "modelo" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "ordenação" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "idioma" @@ -35,7 +35,7 @@ msgstr "idioma" msgid "All" msgstr "Todos" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Ascendente" @@ -44,50 +44,50 @@ msgstr "Ascendente" msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "título" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s foi movido para uma nova posição" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "A instrução para mover não foi entendida." -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "acções" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Confirma a eliminação do item?" +msgstr "" -#: admin/tree_editor.py:437 -#, fuzzy, python-format +#: admin/tree_editor.py:440 +#, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "Recuperar %(verbose_name)s excluído" +msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "conteúdo de aplicação" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "conteúdos de aplicação" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplicação" @@ -144,65 +144,45 @@ msgstr "ficheiro" msgid "files" msgstr "ficheiros" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "imagem" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "texto alternativo" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "Descrição da imagem" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "legenda" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "imagens" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "posição" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "formato" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(sem legenda)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "ficheiro multimédia" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "ficheiros multimédia" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "bloco" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "esquerda" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "direita" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "tipo" @@ -227,19 +207,17 @@ msgstr "Ignorar os avisos de validação do HTML" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo " -"actualizado em baixo antes de continuar: %(messages)s " +msgstr "A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo actualizado em baixo antes de continuar: %(messages)s " -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "texto" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "textos ricos" @@ -247,9 +225,7 @@ msgstr "textos ricos" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só " -"aparece no site após a actualização do feed RSS seguinte." +msgstr "O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só aparece no site após a actualização do feed RSS seguinte." #: content/rss/models.py:22 msgid "link" @@ -283,27 +259,27 @@ msgstr "secção" msgid "sections" msgstr "secções" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "simples" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "linha de título" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "linha e coluna de título" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tabela" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tabelas" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "dados" @@ -315,23 +291,21 @@ msgstr "conteúdo do modelo" msgid "template contents" msgstr "conteúdos de template" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "ligação de vídeo" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: " +"This should be a link to a youtube or vimeo video, i.e.: " "http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "vídeo" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "vídeos" @@ -352,10 +326,9 @@ msgid "published on" msgstr "publicado em" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Será definido automaticamente quando activar a caixa de verificação " -"'publicado' acima." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Será definido automaticamente quando activar a caixa de verificação 'publicado' acima." #: module/blog/models.py:39 msgid "entry" @@ -370,12 +343,12 @@ msgid "tags" msgstr "etiquetas" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "tradução de" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Deixe este campo em branco nas entradas no idioma original." @@ -392,27 +365,27 @@ msgstr "data de criação" msgid "modification date" msgstr "data de modificação" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "tipos de conteúdo" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "data de publicação" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "publicar até" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Deixe vazio se a entrada deve permanecer activa para sempre." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "visível de - até" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Publicação baseada em datas" @@ -440,19 +413,19 @@ msgstr "descrição meta" msgid "This will be prepended to the default description." msgstr "Isto será inserido antes da descrição padrão." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Optimização para motor de busca" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Editar a tradução" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Criar tradução" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "traduções" @@ -465,69 +438,65 @@ msgstr "Isto criaria um ciclo na hierarquia" msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "" -"Não é possível sobrescrever com um tipo de ficheiro diferente (tentativa de " -"substituir um %(old_ext)s com um %(new_ext)s)" +msgstr "Não é possível sobrescrever com um tipo de ficheiro diferente (tentativa de substituir um %(old_ext)s com um %(new_ext)s)" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -"%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." -msgstr[1] "" -"%(count)d ficheiros multimédia adicionados com sucesso a %(category)s." +msgstr[0] "%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." +msgstr[1] "%(count)d ficheiros multimédia adicionados com sucesso a %(category)s." -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "Adicionar os ficheiros multimédia seleccionados à categoria" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "Ficheiro ZIP exportado como %s" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "A exportação do ficheiro ZIP falhou: %s" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "Exportar os ficheiros multimédia seleccionados como ficheiro zip" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Antevisão" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "tamanho do ficheiro" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "criado em" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "tipo de ficheiro" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "informação do ficheiro" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "%d ficheiros importados" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "A importação do ficheiro ZIP falhou: %s" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "Não indicou o ficheiro de origem" @@ -535,7 +504,7 @@ msgstr "Não indicou o ficheiro de origem" msgid "parent" msgstr "ascendente" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -599,23 +568,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binário" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "descrição" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "tradução do ficheiro multimédia" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "traduções do ficheiro multimédia" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Este URL já está tomado por uma página activa." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Este URL já está tomado por uma outra página activa." @@ -623,76 +592,78 @@ msgstr "Este URL já está tomado por uma outra página activa." msgid "Other options" msgstr "outras opções" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "na navegação" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Adicionar página descendente" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Ver no site" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." -msgstr "" -"O conteúdo da tradução original foi copiado para a página recém-criada." +msgstr "O conteúdo da tradução original foi copiado para a página recém-criada." -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "Não possui as permissões necessárias para editar este objecto" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "herdado" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "extensões" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "activo" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "activo" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "URL efectivo" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"URL efectivo. Deve conter uma / no início e no fim, caso se trate de um URL " -"local. Este campo determina a navegação e os URL's das sub-páginas." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "URL efectivo. Deve conter uma / no início e no fim, caso se trate de um URL local. Este campo determina a navegação e os URL's das sub-páginas." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "redireccionar para" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL de destino para redireccionamentos automáticos." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "URL em cache" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "página" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "páginas" @@ -708,28 +679,26 @@ msgstr "Adicione um breve excerto que resuma o conteúdo desta página." msgid "Excerpt" msgstr "Excerto" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "extensão de navegação" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Seleccione o módulo que providencia as sub-páginas, caso necessite de " -"personalizar a navegação." +msgstr "Seleccione o módulo que providencia as sub-páginas, caso necessite de personalizar a navegação." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "Extensão de navegação" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Seleccione páginas a listar como conteúdo relacionado." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Páginas relacionadas" @@ -751,8 +720,7 @@ msgstr "título do conteúdo" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" -"A primeira linha é o título principal. Outras linhas serão sub-títulos." +msgstr "A primeira linha é o título principal. Outras linhas serão sub-títulos." #: module/page/extensions/titles.py:15 msgid "page title" @@ -760,8 +728,7 @@ msgstr "título da página" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Título da página para a janela do navegador. Se omitido assume o título." +msgstr "Título da página para a janela do navegador. Se omitido assume o título." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -772,10 +739,6 @@ msgstr "Títulos" msgid " By %(filter_title)s " msgstr "Por %(filter_title)s" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Procurar" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Confirma a eliminação do item?" @@ -802,18 +765,15 @@ msgstr "Alterar o modelo" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template?
All changes are saved." -msgstr "" -"Confirma a alteração do modelo?
Todas as alterações serão guardadas." +msgstr "Confirma a alteração do modelo?
Todas as alterações serão guardadas." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Confirma que deseja alterar o modelo?
Todas as alterações serão " -"guardadas e o conteúdo de %(source_regions)s será movido " -"para %(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -835,17 +795,21 @@ msgstr "Antes" msgid "Insert new:" msgstr "Inserir novo:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Região vazia" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." msgstr "O conteúdo é herdado da página ascendente, excepto se o indicar aqui." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Adicionar novo item" @@ -900,8 +864,7 @@ msgstr "Recuperar %(verbose_name)s excluído" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" -"Clique no botão 'Guardar' em baixo para recuperar esta versão do objecto." +msgstr "Clique no botão 'Guardar' em baixo para recuperar esta versão do objecto." #: templates/admin/feincms/revision_form.html:12 msgid "History" @@ -914,8 +877,7 @@ msgstr "Reverter %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" -"Clique no botão 'Guardar' em baixo para reverter para esta versão do objecto." +msgstr "Clique no botão 'Guardar' em baixo para reverter para esta versão do objecto." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -952,8 +914,7 @@ msgstr "Seleccione a categoria a aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" -"Os seguintes ficheiros multimédia serão adicionados à categoria seleccionada:" +msgstr "Os seguintes ficheiros multimédia serão adicionados à categoria seleccionada:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -984,14 +945,9 @@ msgstr "%(comment_count)s comentários." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s disse em " -"%(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s disse em %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -1008,6 +964,3 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Obrigado!" - -#~ msgid "Symlinked page" -#~ msgstr "Página ligada" diff --git a/feincms/locale/pt_BR/LC_MESSAGES/django.mo b/feincms/locale/pt_BR/LC_MESSAGES/django.mo index 4d85ce76b814442653d13b2730579ae247e16b81..f37d29a51f432f799592ccab644f0594e28425e4 100644 GIT binary patch delta 4759 zcmYk<33OD|0mkt=2_XnUvWjdvBy1sMCm;TnVMolc^+S+T z%{@2nf}e|6mFxU1?S->s0PL)J2Re+{n)QUjeIS}<5rBt1K0`Q zKy}oD8tA*I30**SdW6s7B!P} zMo*h&7;34D?fz`+#=ajl@Kwm%%qHxNdoZ+_!clv|OxE)*_RCQ-XhL1M6G!7g)RJCD z&3yRn&Wy*PW;h8o!0D)tR-qf4Q0*K?b$kxh{-xVlf7&vCr9utdM6E;&!`6&DqGr&S zpCLE`XW=5$dGDdF`_S%xYW)J$;Z;;eH_(r*_PC$MHG%r>tiNUyqGA-D!e!W=M|BXc zLOp~>Fbl6@8FuH<&cmgckNZ&_eU7?yU!ex@Pb|V#9F9f3oLl+?Y5>oMDCokC_P`d@ z((Ojw(>Ia3W8Ozya255me~Wt9{%4K7!|5;{wZy$p=V#dceCsIGicPl1Ll4>mUeuD- zpdPxQ-G9Wo3^lWr7#X>BqpfeU`!AygxED3RBdB&ypgKNnJ?|JYA5&1npIfh@R^%Jh zOm3hqY=5U?JgVXDs3lHAb&!MVxWGCRwQ>_s&)8hl#1^Ao-{ly2|2I(JV`X-r8aj+x z`exLJ=sc?74^SOnMs<7zb^gEY@tdfLw0Aobh(qlsp|0zOYBv=%!J!x*qEJXd2PUIt z`VgvvYSf6A*!?H%{#sN6O{nvCq6WAhb!(bY9iBoB@EuhBd#LZjMbyBqU`P#pO(8N9 z)P*-uOVqBnvoa~D_t7`sX_v8CGpW^FrXtcUH3QKjMq{9tRHC1RQfkBQP4wi9TPDs!LL6R zM`F($V`_0W>W|Plya%g@#{u*lF|3wWbD$hB;1BP_(k|}6u zGEw_Qs0&I_OI3kd@&Lx+!>D__67^}_YL6d5y>=%t5kIo^SFPV+0`;w^fh6Q}|26Wi zOj{kLp=Ok2EwJ^&Q8O+=4Xnf-pJ9*BLA5jA9$$nS*iuZy^{9vN6;wM%Q2m_9XZ_XS z87gkY^QisHs1bf?PrQbDn7%`;M5n<{gDI#P^+kOjhN2s%qdIQDczha@@C8&muc4lu zmJkIk`P;VQGwjU%71WHbTcZn{fptMO+!ZyGfvATn794bk>G{YSQ8{7$pwSMgC2Ao@G@2I)$4=d~4* z4UrNr8*V3~?EWGAJ<)rjErsaG_yZ{=50O_$Gg(Vg`tx&u{Fqb{ZE=mR_@vMjXD9Nj zzuO+-BV)-((zZQf3w`l#5InAF_}vBh};ul0c@C29iv)rID>nw(*t+=7f8wvH3Mfneq|zqdND&>O7rd)$+}!C*zDH{hP&3j}@D6*UVN zyN6dT7^$u+e3ikhvWh~ksxGhdmiscN`MgygcS(&uSXa(SeC`3G{ociu3)9^L?C9(3 z>$8GtzjEF{UqfUTwf>sKBI6iGwm$qI!?nrIpwzTx9 tyE`^EC1f;SPumkd(5JRTI3x3*E1Z;lEjk>VzuOf)I@lEzJ~brS^?$S>7?%J5 delta 4956 zcmZYC32;>P0mt!w0wfU5gfpR$B?JhBgj|FW4#SmDSOeu!4olW#2@6R!Y&H~XbS)l; z7O^h0f)oiN5Q|V*K#;2lcyP5^87*zKN*x(Gg|Qv9rIq&k+xL$%oxb6>pa1*sd;jz8 zZrE1$kw5ftQrnG&<9+fSvM0`%nuY3k9tN=z+tR=Jh=LmUqbl%o9DvtRH+ErEYPbicpbHCd zG>*V})XMEd#%2zomioLszkJ74&5)Pz|g^t;A~7 z`)g1$e+KzyT6ihM)3^X{qpqLJMY?|h>fCExit5;pYOe_c_-G32uciLVUYNq8sTuV{ z&2TV|#~OSb_u?=t;E~ot>A`FaVTn%uD>tA9vKh;8SBSzG3O7-E zJnSxK07a-9OHlP?sHL2R+T&_uJ53X+;V^38n^2#EX4IDKu^vQqd;+!f=TX;(erGE_ zwcbQ6;Wzez_R6GMBR75dIB}`cTh8a57qw1)~l!iT#Fhq=I<1=ly^`MVNaJc z!z|S2dlagpsi<$f`%n!oMQw#2^+oj|+e?d*)7OLHZH1=OJ zNKSJa9E7o)XQFP*Mvb@t)$!e^4oWc?!&ab&^NW0jwS~je`RM9>)cIl@gb$&%a0hB2 z`>_O%rL+FDVZNb)PoQxPbVfK1qaQacq`n%};8tvh2dzg@pYv0w0p7Cp|3gPnmtg2Slaidx$9 zs0m!bIJ|*s?-uG=iOaB`|0D|Ss7OH#z=aRvPE-?&vx$1wB}><_kT2nE?iK8x^Ox^iE~j8 z*C(hg>OS0=K{9Fu2A~^PU>HxMew6Obaqe4-C7d6}dc1>r-_OffY{rmg@CgNVd<{F| zO`L)M!U^ckbL!WlR^$cLfL^loEy!M)gQ%6dWY4dmu8Uz7x-TB1D~Q^PlzjX7Pp3kA zpNskmo?MGb5qY9M2=E6zYQRDtTqhq}HVyWmQDz6LeG^{DGMqMorWAqr|> zKWa&iq8dJnn%QO47swar!g&7R(*QEC8;-{A=*FH{fo*XGYD*rp=Nqsy=bKO~w96Wb zP|%1^q8ff1HJ~e~CA@0izkwRySE$dqz7};|U)0l|j_RNcb=@57go|u_4QgUPL{01| zq~DO)LO~tvK;5vif+dts7~6hvOeL?8kY?0+ETGU#zGo{gp=SDP5+oI57CA+RlaoZ>oF|A@@Cm|~UG#rX zVCu-zq>WBEhLUY6aOiu5Z3vkI6tus;B9loG8AKig|PNtM;~%ew8S?Q#*;H-x~=;eexF<(Sp9 znlQzdJvfQHY0q1Eo3 zQRjD6dg_Bdf8CJC?ZjU3kq*gAV_cp<_p+jX{5{C+Mqm1-wlzj9gRdTLor8}H&^WO%=IG3^4r>LtO*QCF{+^n@AHXJ<_ec)8PGmo>=~ z^cK7Fa&q&sa*DEY3thQI#knKHscC&f)D&jrj&S7^73Yn}%;89Idm4gSvjd*Gh8j=M zA1HQ}HTr6ncmuUwSDC-A%2(?e)8MW3)&;#KK~H1ASJ&8(?GIFs&wyxKW~#$7eu zYHwYYXGr9p^yTg2W(53|je*F~VXw#JYGJCp{A&pMSipKuz|*=kOx2@t`5T;NJKfB> q`6K@9FP-)BM;7JniD~a`Sl;LjRCyu^1+lU5T2x=q6X{skGv>d%lqZ}3 diff --git a/feincms/locale/pt_BR/LC_MESSAGES/django.po b/feincms/locale/pt_BR/LC_MESSAGES/django.po index bae07c6d7..d876a2baa 100644 --- a/feincms/locale/pt_BR/LC_MESSAGES/django.po +++ b/feincms/locale/pt_BR/LC_MESSAGES/django.po @@ -1,33 +1,33 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: -# Guilherme Gondim , 2012. +# Guilherme Gondim , 2012 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" -"Last-Translator: Guilherme Gondim \n" -"Language-Team: LANGUAGE \n" -"Language: pt_BR\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" +"Last-Translator: Matthias Kestenholz \n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/feincms/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Language: pt_BR\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "modelo" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "ordenação" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "idioma" @@ -35,7 +35,7 @@ msgstr "idioma" msgid "All" msgstr "Todos" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Ascendente" @@ -44,50 +44,50 @@ msgstr "Ascendente" msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "título" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s foi movido para uma nova posição." -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "A instrução para mover não foi entendida." -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "ações" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Confirma a remoção do item?" +msgstr "" -#: admin/tree_editor.py:437 -#, fuzzy, python-format +#: admin/tree_editor.py:440 +#, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "Recuperar %(verbose_name)s removido" +msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "conteúdo de aplicação" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "conteúdos de aplicação" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplicação" @@ -144,65 +144,45 @@ msgstr "arquivo" msgid "files" msgstr "arquivos" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "imagem" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "legenda" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "imagens" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "posição" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(sem legenda)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "arquivo de mídia" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "arquivos de mídia" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "bloco" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "esquerda" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "direita" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "tipo" @@ -227,19 +207,17 @@ msgstr "Ignorar os avisos de validação HTML" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"A validação HTML produziu %(count)d avisos. Por favor, revise o conteúdo " -"atualizado abaixo antes de continuar: %(messages)s" +msgstr "A validação HTML produziu %(count)d avisos. Por favor, revise o conteúdo atualizado abaixo antes de continuar: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "texto" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "textos ricos" @@ -247,9 +225,7 @@ msgstr "textos ricos" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"O feed RSS é atualizado por várias vezes ao dia. Uma alteração do título só " -"será visível na página após a próxima atualização do feed." +msgstr "O feed RSS é atualizado por várias vezes ao dia. Uma alteração do título só será visível na página após a próxima atualização do feed." #: content/rss/models.py:22 msgid "link" @@ -283,27 +259,27 @@ msgstr "seção" msgid "sections" msgstr "seções" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "simples" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "linha de título" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "linha e coluna de título" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tabela" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tabelas" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "dados" @@ -315,23 +291,21 @@ msgstr "conteúdo de modelo" msgid "template contents" msgstr "conteúdos de modelo" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "ligação de vídeo" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Isto deve ser uma ligação para um vídeo do Youtube ou Vimeo, i.e.: http://" -"www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Isto deve ser uma ligação para um vídeo do Youtube ou Vimeo, i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "vídeo" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "vídeos" @@ -352,10 +326,9 @@ msgid "published on" msgstr "publicado em" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Será definido automaticamente assim que você ativar a caixa `publicado` " -"acima." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Será definido automaticamente assim que você ativar a caixa `publicado` acima." #: module/blog/models.py:39 msgid "entry" @@ -370,12 +343,12 @@ msgid "tags" msgstr "etiquetas" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "tradução de" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Deixe este campo em branco para entradas no idioma original." @@ -392,27 +365,27 @@ msgstr "data de criação" msgid "modification date" msgstr "data de modificação" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "tipos de conteúdo" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "Otimização para motores de busca" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "publicar até" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Deixe em branco se a entrada deve ficar ativa para sempre." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "visível de - até" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "Publicação baseada em datas" @@ -440,19 +413,19 @@ msgstr "meta descrição" msgid "This will be prepended to the default description." msgstr "Isto será inserido antes da descrição padrão." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "Otimização para motores de busca" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Editar a tradução" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Criar tradução" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "traduções" @@ -467,63 +440,63 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "Adicionado com sucesso %(count)d arquivo de mídia em %(category)s." msgstr[1] "Adicionado com sucesso %(count)d arquivos de mídia em %(category)s." -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "Adicionar arquivos de mídia selecionados à categoria" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Pré-visualização" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "tamanho do arquivo" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "criado em" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "tipo de arquivo" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "informação do arquivo" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "%d arquivos importados" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "Nenhum arquivo de entrada fornecido" @@ -531,7 +504,7 @@ msgstr "Nenhum arquivo de entrada fornecido" msgid "parent" msgstr "ascendente" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -595,23 +568,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "Binário" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "descrição" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "tradução do arquivo de mídia" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "traduções do arquivo de mídia" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Esta URL já está ocupada por uma página ativa." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Esta URL já está ocupada por outra página ativa." @@ -619,76 +592,78 @@ msgstr "Esta URL já está ocupada por outra página ativa." msgid "Other options" msgstr "Outras opções" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "na navegação" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Adicionar página descendente" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Ver no site" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "Você não tem as permissões necessárias para editar este objeto" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "herdado" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "extensões" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "ativo" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "ativo" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "URL efetiva" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Substitui a URL de destino. Certifique-se de incluir barras no início e no " -"final, se for uma URL local. Isso afeta tanto a navegação e URLs de " -"subpáginas." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Substitui a URL de destino. Certifique-se de incluir barras no início e no final, se for uma URL local. Isso afeta tanto a navegação e URLs de subpáginas." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "redirecionar para" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL de destino para redirecionamentos automáticos." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "URL em cache" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "página" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "páginas" @@ -704,28 +679,26 @@ msgstr "Adicione um breve trecho que sumarize o conteúdo desta página." msgid "Excerpt" msgstr "Trecho" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "extensão de navegação" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Selecione o módulo que fornece sub-páginas para esta página se você precisa " -"personalizar a navegação." +msgstr "Selecione o módulo que fornece sub-páginas para esta página se você precisa personalizar a navegação." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "Extensão de navegação" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "Selecione as páginas que devam ser listadas como conteúdo relacionado." -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "Páginas relacionadas" @@ -747,9 +720,7 @@ msgstr "título do conteúdo" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" -"A primeira linha é o título principal, as linhas subsequentes são sub-" -"títulos." +msgstr "A primeira linha é o título principal, as linhas subsequentes são sub-títulos." #: module/page/extensions/titles.py:15 msgid "page title" @@ -757,9 +728,7 @@ msgstr "título da página" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Título da página para a janela do navegador. Por padrão, o mesmo que o " -"título." +msgstr "Título da página para a janela do navegador. Por padrão, o mesmo que o título." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -770,10 +739,6 @@ msgstr "Títulos" msgid " By %(filter_title)s " msgstr " Por %(filter_title)s " -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Procurar" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Confirma a remoção do item?" @@ -800,18 +765,15 @@ msgstr "Alterar o modelo" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template?
All changes are saved." -msgstr "" -"Confirma a alteração do modelo?
Todas as alterações serão salvas." +msgstr "Confirma a alteração do modelo?
Todas as alterações serão salvas." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Confirma a alteração do modelo?
As modificações serão gravadas e o " -"conteúdo de %(source_regions)s será movido para " -"%(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -833,19 +795,21 @@ msgstr "Antes" msgid "Insert new:" msgstr "Inserir novo:" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Região vazia" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"O conteúdo é herdado automaticamente da página ascendente. Para mudar este " -"comportamento, adicione algum conteúdo." +msgstr "O conteúdo é herdado automaticamente da página ascendente. Para mudar este comportamento, adicione algum conteúdo." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Adicionar novo item" @@ -900,8 +864,7 @@ msgstr "Recuperar %(verbose_name)s removido" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" -"Pressione o botão de salvar abaixo para recuperar esta versão do objeto." +msgstr "Pressione o botão de salvar abaixo para recuperar esta versão do objeto." #: templates/admin/feincms/revision_form.html:12 msgid "History" @@ -914,8 +877,7 @@ msgstr "Reverter %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" -"Pressione o botão de salvar abaixo para reverter para esta versão do objeto." +msgstr "Pressione o botão de salvar abaixo para reverter para esta versão do objeto." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" @@ -952,8 +914,7 @@ msgstr "Selecione a categoria a aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" -"Os seguintes arquivos de mídia serão adicionados à categoria selecionada:" +msgstr "Os seguintes arquivos de mídia serão adicionados à categoria selecionada:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -984,14 +945,9 @@ msgstr "%(comment_count)s comentários." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s disse em " -"%(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s disse em %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -1008,6 +964,3 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Obrigado!" - -#~ msgid "Symlinked page" -#~ msgstr "Página de ligação" diff --git a/feincms/locale/ro/LC_MESSAGES/django.mo b/feincms/locale/ro/LC_MESSAGES/django.mo index 1a5a08c3e1bb8706cce286243da75b1ed73c0972..3ca2ed362b6709b48bbfa4d15a049563e9d616a4 100644 GIT binary patch delta 3071 zcmX}ueN5F=9LMo<5sTD7dAO*MUVOxd3tSWwFiF5bB{cB?MNq&CUPMs1q?mfsthv&r zyS8O5EL*Mz$6B}MhO6cLqgk`3sWr56(+|Ky^Ugw`dr^vb6AJd@j7b7hI4mWSb|N=Z?;g$#S1tC<3>a#o`dDI7oY|{gqrXOYGvL) zC3*sr@iSye%>~r?zoWL~Z`5uMpl&FRWo8jf3I=rIc-t`z!z+R6FSY%PPun|-LYIfOc|7d78oNjxID zw>~cW6M@p)82FWUBD)Oklx10O~H%)1;k&Znrv&Y>o{gfVypb=@@# zuec`AM7L2(c@J+nxR}p^w%|SoZ9y^zeJQ5nA}m1-^b%?-4kLf&7>8=?M?R06-DZs@*k$7Hbnx}#(^UKx)>4UmD#Jjb?YqY^4domXYs zD{Z?TwX`j$@5ByNVh8N+Z=;@_KGb>r$a8MK&Im-F{+o1Yf&tW1`oOqI#!ghmnW%)^ zs5{C-ZB+&8x++v+%TedmqpoX4oww1t1vT+j)Jh)=P*G;DqE_O#^*s#lJu0CPYM?X7 zn`O?T1LqO-#A<@v!w+OJ>H${Km_5XFBA?J)dMmn#EFv(617qn$Fv|%q!E+M+H?t6x z#CAeuDxvLZC(4Ov*=8#ft?Qyc;M2rXVk^B zO6c9?)ef&lCC(-qh$fg5}Sz0#8X5q5x#Bhr}iRRCQxa! zjm7vFF_RciWD|OqRaywWH7eQ??Q0EDL_|vml^M|nb`p93pNRHp*;V)$nKi^RH7GlX z4dGhkpw}+lwq4e}sHc2AvC;Nz#%GBkwk;MAdR?0dC*dPh<`RL%aFzdFV4kh7u`BOX%&Gq(-D@Q6sNfxZ*15aZSu@_O+9<3_I3?fvUr)hwA0(*_jR27G@n$C`3O=`8HDENNrsL;jK>eygz`mWIB W^vXe@nXajhP;el57yx#9E&^fChW%>jES0espN3tI0o=6s$&&bZ^nhl*k(0qg2!<*Za{K1Pulht zyp8rYoP~YJKl2TTe!PebZK7mfi7#U+^P7`Y^srx`GCYqO;38&XHtDKk5o*E;R3g>b zj5Vl!{r3DmoJjis>i)BsiWg8TaS@-#LY}Ue`OQ02w1gLM2Bu{g(}H(nIria9{0fyw z3d>WE8K{9*pb~OXE7gWd+`}w<5w*g7sFiyk)$aq0>Ro+8CB6cv3C^RIZWwjrRong( z^`xncuJakF`^KZ5bP6hgV%x5?&OuFFgX%Zmwi`29eJtGCB6rh$RX=t)cD7&r%)^LHQs`kGFg9RtaZ}ImX4ZW0I%>c<$UjrV zAsLsWCT>Pe>_gqR0X5+!)Dv$-CBEIZUqSWTf&4RlQI4AUJ$vF))RSF64LpQO@QQ8! zZQEnmlNvY+b$>2u;zHEKrKp4|P)lBoe9xxVUT;G6k3LF8H?Bct=CkefsDUD=37$gc zHrr4Gy@5(_FRK3lj>03Te#cM=oj^@=8nvQl@v|gjenwtJ)a>U)=)xfCot)>uHFFso zFy+?7fQ_hEvkY~g4ma7B^j}6@3Zy3SY+uu^%CU#)GIO|G{1#!g|`5aVJ(x;I{)$<9&GD9elv}0B*$|oUZeE ztp98(B~AqE_xN)VDE; zb=UbU)cFbd(L|+?6PmCDHBl96;5y_-&orPqtVXRw0QKY>P!n%Qt;|mAe$*~GY5f*8 z&M+#GKTr=gCR&gO_d1I&irOFF_lnxlnBLZiNjNHzin?q-cGzc$5G3!qSf;g$!btq6Bq{{ zBUqUKl?Q3PKs-rAgB%)&a-xXP4~2@BcnzUl@!!%&L*I#tc7TdL)N0~c;!a`|p;DS4 ze(dHL{!ja*L_He+Q%GA%@3MkePH0Q5C*~4ch}8r?X2vB{wh9cMPQ7w5Kq{){ufl~ z(ZQ+datfygg6*C^vc?N~?f#;Tj+q(?J1uU97Yv7r%>6!})6y1f_c3dZ(wNL(@CQv!PYh}wkm6AQd;ApB_*{HKRv^tk~-J(S2^XSW#uKMl_g~rPFZDD z*T?A&zDRFss>c1kO&%43JJUrk@&hFUw_R_>34V{>zwWBYQNVt?n1&zKq*?2Zg} zJMI2ff5JF@Q&LpM!cz_PijZG;y{tp$&Y>5B> diff --git a/feincms/locale/ro/LC_MESSAGES/django.po b/feincms/locale/ro/LC_MESSAGES/django.po index e811171fc..60c3517bd 100644 --- a/feincms/locale/ro/LC_MESSAGES/django.po +++ b/feincms/locale/ro/LC_MESSAGES/django.po @@ -1,35 +1,33 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: -# GABRIEL KOVACS , 2010. +# Gabriel Kovacs , 2010 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: Romanian (http://www.transifex.com/projects/p/feincms/" -"language/ro/)\n" -"Language: ro\n" +"Language-Team: Romanian (http://www.transifex.com/projects/p/feincms/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?" -"2:1))\n" +"Language: ro\n" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "șablon" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "ordonare" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "limbă" @@ -37,7 +35,7 @@ msgstr "limbă" msgid "All" msgstr "" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "" @@ -46,50 +44,50 @@ msgstr "" msgid "Category" msgstr "" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Modifică %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "titlu" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "acțiuni" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Confirmți ștergerea obiectului?" +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "conținutul aplicației" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "conținuturile aplicației" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "aplicație" @@ -146,65 +144,45 @@ msgstr "fișier" msgid "files" msgstr "fișiere" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "imagine" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "legendă" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "imagini" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "poziție" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(fără legendă)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "fișier media" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "fișiere media" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "blochează" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "stânga" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "dreapta" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "tip" @@ -231,15 +209,15 @@ msgid "" "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "text" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "text formatabil" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "texte formatabile" @@ -247,9 +225,7 @@ msgstr "texte formatabile" msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" -"Fluxul RSS este actualizat de mai multe ori pe zi. O modificare a titlului " -"va fi vizibilă in prima pagină după următoarea actualizare a fluxului." +msgstr "Fluxul RSS este actualizat de mai multe ori pe zi. O modificare a titlului va fi vizibilă in prima pagină după următoarea actualizare a fluxului." #: content/rss/models.py:22 msgid "link" @@ -283,27 +259,27 @@ msgstr "" msgid "sections" msgstr "" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "simplu" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "titlu" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "titlu rând și coloană" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "tabel" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "tabele" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "data" @@ -315,23 +291,21 @@ msgstr "" msgid "template contents" msgstr "" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "legătură film" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Aceasta ar trebui să fie o legătură către un film de pe youtube sau vimeo, " -"de ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Aceasta ar trebui să fie o legătură către un film de pe youtube sau vimeo, de ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "film" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "filme" @@ -352,10 +326,9 @@ msgid "published on" msgstr "publicat la" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Va fi trimis automat în momentul in care bifați butonul `publicat` de mai " -"sus." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Va fi trimis automat în momentul in care bifați butonul `publicat` de mai sus." #: module/blog/models.py:39 msgid "entry" @@ -370,12 +343,12 @@ msgid "tags" msgstr "etichete" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "tradus de" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "" @@ -392,27 +365,27 @@ msgstr "data creerii" msgid "modification date" msgstr "data modificării" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "data publicării" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "sfârșitul publicării" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Lasă gol dacă înregistrarea ar trebui să fie activă întotdeauna" -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "vizibil de la - până la" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "" @@ -440,19 +413,19 @@ msgstr "descriere meta" msgid "This will be prepended to the default description." msgstr "Va fi inserată la descrierea predefinită." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Modifică translatarea" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Creează o translatare" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "translații" @@ -467,7 +440,7 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." @@ -475,56 +448,56 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Pre-vizualizare" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "creat" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "tipul fișierului" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "" @@ -532,7 +505,7 @@ msgstr "" msgid "parent" msgstr "părinte" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -596,23 +569,23 @@ msgstr "" msgid "Binary" msgstr "Binar" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "descriere" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "traducere fișier media" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "traduceri fișier media" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Acest URL este deja rezervat de către o pagină activă." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Acest URL este deja rezervat de către o altă pagină activă." @@ -620,75 +593,78 @@ msgstr "Acest URL este deja rezervat de către o altă pagină activă." msgid "Other options" msgstr "Alte opțiuni" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "în navigare" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "Adaugă o pagină copil" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Vezi pe site" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "moștenit" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "extensii" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "activ" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "suprascrie URL" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"Suprascrie URL-ul țintă. Aveți grijă să scrieti / la început și la șfârșit " -"dacă este un URL local.Aceasta afectează atât navigația cât și subpaginile." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Suprascrie URL-ul țintă. Aveți grijă să scrieti / la început și la șfârșit dacă este un URL local.Aceasta afectează atât navigația cât și subpaginile." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "redirecționare către" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "URL-ul țintă pentru redirectări automate." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "URL în cache" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "pagină" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "pagini" @@ -704,28 +680,26 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "navigare extinsă" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" -"Selectați modulul care furnizează subpaginile pentru această pagină dacă " -"doriți să personalizaţi." +msgstr "Selectați modulul care furnizează subpaginile pentru această pagină dacă doriți să personalizaţi." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "" @@ -755,9 +729,7 @@ msgstr "titlul paginii" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Titlul paginii pentru fereastra navigatorului. Implicit este la fel cu " -"titlul paginii." +msgstr "Titlul paginii pentru fereastra navigatorului. Implicit este la fel cu titlul paginii." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -768,10 +740,6 @@ msgstr "" msgid " By %(filter_title)s " msgstr "După %(filter_title)s" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Căutare" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Confirmți ștergerea obiectului?" @@ -790,9 +758,7 @@ msgstr "Nu pot șterge obiectul" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Nu se poate șterge obiectul, deoarece este părinte la cel puțin incă un " -"obiect." +msgstr "Nu se poate șterge obiectul, deoarece este părinte la cel puțin incă un obiect." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -803,14 +769,12 @@ msgid "Really change template?
All changes are saved." msgstr "Doriți ștergerea șablonului?
Toate modificarile au fost salvate." #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"Doriți ștergerea șablonului?
Toate schimbările au fost salvate și " -"conținutul de la %(source_regions)s a fost mutat la " -"%(target_region)s." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -832,19 +796,21 @@ msgstr "" msgid "Insert new:" msgstr "" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Regiunea este goală" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" -"Conținutul de la pagina părinte este moștenită automat. Pentru a suprascrie " -"acest lucru, adăugați conținut" +msgstr "Conținutul de la pagina părinte este moștenită automat. Pentru a suprascrie acest lucru, adăugați conținut" -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Adaugă un obiect nou" @@ -980,8 +946,7 @@ msgstr "" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " msgstr "" diff --git a/feincms/locale/ru/LC_MESSAGES/django.mo b/feincms/locale/ru/LC_MESSAGES/django.mo index fd265e16a6a558642709d4542c638eb48b37de1b..12c27af3bfe277c3838077efcbb144cdd2f44110 100644 GIT binary patch delta 2767 zcmZwIYiyHM9LMofm;)wbTS1X2TgSL=biIthD3i+u!VsYX0y>d(quUBwSKE#WQ5(Ui z350|-NF)M52oc0YoT9`RVj$6INWc&i<1Juz*pL5Rhob#O9 z^X$)tJN2pWojC^$DNZ~S*5v&`<59ysT#x&zOydRx;#!SU39Ea_5G+BA4IL-aeMtkWRcB9Olj%AAfpjoNBTB5P#yhd9kliTpk|cM{-|Ro zs$60%N41-2^`e%(7WKe|sQVjHTfMq~^;c$-y|KmGfto=SHJ~2UK=+^qx)0USYp9No zViBIU^&g=Q<3&`v%eMXs>i#cL1N*Lk_1A-bv^V~WI!u4y1k9nJ0Zu|axEwWeFREP~ zY9I}$nXf=~9JJRr*z22718K44?Wp@=DKhGKhrO@|M^Jvn-mn)n;sdA$zK(_5Z~}Kx zeven85e;1zmz%4?>sJCLe1oF+>JB%TIjT& zK^Km@FWaF9wKZ$-0B%LiafQN83YJj(_gQy9NW;x4w zzL`u$16YFUAZTsH>6CX^kDwY}MlI#n$YjhdTQ()x2j!ye)$wsE%JE%P`77&BsJ*;{Owts&SYGs?>YJ@QQ3L8jt>l}iE&Bj9z)w;2SFJyw z>IYn@?1%@c(8zK)s@j4A)Ig@7MqZ7&9k!b^Cg7#b|}p!qa}9{yg+6Fv5n9hv51&L zXyue1B(yrK2t7aZUu%mpq_xCS!cVLtlss87U%r*(A0Zaoy6O0s&CkUE@uV#`p|({k zsZ>YkeCW&f1VQp=mXQxy=Hrv8;zxU{{Ze|IaA$JaZ+d?Ez?ku=c50$TBT-Fcju~oK zBSZ_Kjcg`DL@P0h*iMuZj}lu6r8Yt@@_J$!QBNr8L=B}FnR!GlQKn_5daY-Zt5MP9l%?|A=bd6!1?_vOFg zNCygTrppRXr>_?Fr8<(ySis|Hk0d*KTB=&RyF6{-NVK&pF>EA}=m{tCf@{{h8{*+m zGSVG&FAXKb0hizFt9JXmZhwu-=L`7!m0rKs%Z=`};T@60|K8`FAMn*wdP#Y!LW!h1 zeW7S^{o0;HA`*(aX4=8@_V!jKQtqHi|J?W$~=~$5d*?GJF_V}H-{fXj=k^QG8|KjLBT)NMZt}grJU)R$c AL;wH) delta 2822 zcmX}t3rv+|9LMqJ2nZqw2Q)6G983{ZkfVY`Ubv`uIa-mI3@h=7fD#CT7Oow2U1!bQ ztHoL|Tf>%)QcyA6u!~zQZ5_9)Wh+}|Q_JbhEmw2v`#a~+XXpQZp67Yr_qo0A^Pbyf zx5@**Bt`Buq%Fk##CH+KypOL%b0DS08nYVHa3r?lSbP)X@Pzd%jG}xFX~O(u%NKAk z|9B94ba*4Ek{hHedp7#&~=Q@54RFjpiU`;Q(qNmoO1;B0m#B zWh5q8hoc6VhB}{t>GW?Vl9@)uJS@Pi$j=<+ppFM@`3x3O{t-2!Bu_J|x1a{{0_wh3ZTSsJ|7I^4HT1T<-~)TXN2rE-aT14-%21DDF=}ATkv@$dbzQUdIa|LSHN#z~ z4))mcK5G~1z5~`CRKNWRtiL+^)LwWR_3VSz^Y+5utyfVqxq%wcKd6C5@!&PkVW@$O zw0cnOk3%=++xjxpOInf0`m2FO_QX=u4J%P2T#M>(J?gq<WY2JWCbh+rCOC=mzY2-Nvh)WAoh z+RMRDT+A5TDPLvFOvD=A%yQg~+J=F1WHQKHLp2c3wA4TBLMNK+X79>ow$O{^c+o z-3(tdT7WyS4YeC?qX$=|hTD4{8Jl?*cViD~B6HGMCGG!ZWT-O%tile|3~wQWH8aw~ zGpj@msK%CCkR4`T#L2kF)}KPH+z-h6X?{a3`AuZTrjXC*3Vaz4(!aStMoYJo@2_s` z#JBK6)JRKNM_GxQi60-pXHoCUJE(zlq1riO{Svb%pSQY3hwsluO=Ko&(q^HpSc~eY z8P)I(WYA`(t>2HjvCn!6HK4Po>;FJj-&{xDI}^?G)P&Md?T)n;pjLKX2J5dIS5Yw@ zYfv}5j_Rnx)^{O`WWGVYoL5lS-9QcCKU4>ap76?KqRMlv%TbTG7Fi6l4fCHK0z^1U|Osj|FVz zGt}Sj8C$-BF3L*F!k9;`cWJhnjn-Q95(|i>woV_XJYu;mH=!mn&z6~gc*GB4D=}9U zHfbezl%an!RXwc(X*Mx|(2RUU4WZdCA!ZOtT1};~gdR~Hp_R}U)u($iQLO#1<v|E&jUR z-1J zS2?qiHaR^>*HW^Bhl59heV*XS;6U&Q$Kz+W2ao6Ub|$wEj_x4eA3W5Xl%5|EeK>f6 kOZt0DM*ZoEA%8U3!>R0yU9LDTJ9&0n@Q`YpW1i3d2Q>6Ch5!Hn diff --git a/feincms/locale/ru/LC_MESSAGES/django.po b/feincms/locale/ru/LC_MESSAGES/django.po index ab85f2006..ab94e04a9 100644 --- a/feincms/locale/ru/LC_MESSAGES/django.po +++ b/feincms/locale/ru/LC_MESSAGES/django.po @@ -1,34 +1,33 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: -# Mikhail Korobov , 2009. +# Mikhail Korobov , 2009 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: LANGUAGE \n" -"Language: ru\n" +"Language-Team: Russian (http://www.transifex.com/projects/p/feincms/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +"Language: ru\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "шаблон" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "сортировка" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "язык" @@ -36,7 +35,7 @@ msgstr "язык" msgid "All" msgstr "Все" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "Родитель" @@ -45,50 +44,50 @@ msgstr "Родитель" msgid "Category" msgstr "Категория" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "Изменить %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "заголовок" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "Узел \"%s\" был перемещен на новое место." -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "Перемещение не удалось. Непонятная команда." -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "действия" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "Вы уверены, что хотите удалить элемент?" +msgstr "" -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "приложение" @@ -145,65 +144,45 @@ msgstr "файл" msgid "files" msgstr "файлы" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "картинка" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "подпись" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "картинки" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "расположение" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(без подписи)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "блок" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "слева" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "справа" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "тип" @@ -230,15 +209,15 @@ msgid "" "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "текст" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "" @@ -280,27 +259,27 @@ msgstr "" msgid "sections" msgstr "" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "таблица" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "таблицы" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "данные" @@ -312,23 +291,21 @@ msgstr "" msgid "template contents" msgstr "" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "ссылка на видео" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"Это должно быть ссылкой на видео, размещенное на youtube или vimeo, " -"например, http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Это должно быть ссылкой на видео, размещенное на youtube или vimeo, например, http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "видео" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "видео" @@ -349,10 +326,9 @@ msgid "published on" msgstr "опубликовано" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Будет установлено автоматически, как только Вы отметите пункт \"опубликовано" -"\" выше." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Будет установлено автоматически, как только Вы отметите пункт \"опубликовано\" выше." #: module/blog/models.py:39 msgid "entry" @@ -367,12 +343,12 @@ msgid "tags" msgstr "теги" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "Оставьте поле пустым для записей на основном языке (%s)." @@ -389,27 +365,27 @@ msgstr "дата создания" msgid "modification date" msgstr "дата изменения" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "дата публикации" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "дата окончания публикации" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "Оставьте поле пустым, если запись должна оставаться активной навсегда." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "" @@ -437,19 +413,19 @@ msgstr "" msgid "This will be prepended to the default description." msgstr "" -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "Изменить перевод" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "Создать перевод" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "переводы" @@ -464,7 +440,7 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." @@ -472,56 +448,56 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Предпросмотр" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "размер файла" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "создан" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "тип файла" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "" @@ -529,7 +505,7 @@ msgstr "" msgid "parent" msgstr "родитель" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "путь в URL" @@ -593,23 +569,23 @@ msgstr "" msgid "Binary" msgstr "Двоичный" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "описание" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "Этот URL уже занят активной страницей." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "Этот URL уже занят другой активной страницей." @@ -617,73 +593,78 @@ msgstr "Этот URL уже занят другой активной стран msgid "Other options" msgstr "Другие параметры" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "в навигации" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "расширения" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "активная" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." msgstr "" -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "редирект на" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "страница" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "страницы" @@ -699,26 +680,26 @@ msgstr "" msgid "Excerpt" msgstr "" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "" -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "" @@ -748,9 +729,7 @@ msgstr "заголовок страницы" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" -"Заголовок страницы для окна браузера. По умолчанию = просто заголовку " -"страницы." +msgstr "Заголовок страницы для окна браузера. По умолчанию = просто заголовку страницы." #: module/page/extensions/titles.py:43 msgid "Titles" @@ -761,10 +740,6 @@ msgstr "Заголовки" msgid " By %(filter_title)s " msgstr "" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "Искать" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Вы уверены, что хотите удалить элемент?" @@ -783,9 +758,7 @@ msgstr "Не выходит удалить элемент" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" -"Не выходит удалить элемент, т.к. он является родителем как минимум для " -"одного другого элемента." +msgstr "Не выходит удалить элемент, т.к. он является родителем как минимум для одного другого элемента." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -798,8 +771,9 @@ msgstr "Точно сменить шаблон?
Все изменения #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -822,17 +796,21 @@ msgstr "До" msgid "Insert new:" msgstr "Вставить перед этим элементом" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "Регион пуст" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." msgstr "" -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Добавить элемент" @@ -968,14 +946,9 @@ msgstr "%(comment_count)s комментариев." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" Пользователь %(comment_username)s сказал " -"(%(comment_submit_date)s)
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n Пользователь %(comment_username)s сказал (%(comment_submit_date)s)
\n " #: templates/content/comments/default.html:28 msgid "No comments." diff --git a/feincms/locale/tr/LC_MESSAGES/django.mo b/feincms/locale/tr/LC_MESSAGES/django.mo index d5c7d013542586d3d6bc6d06df409c0f656ea26e..878620bbb3e6a628aa139c3b64c8b0dcfb20abce 100644 GIT binary patch literal 15383 zcmbuF3zS_|dB-;f5Q73DA`+E@5R*XWP7r5-i-`4s55NaCQXeQ*OB7tKYO43`1ZHI*WQzVJo3QX4A0}xOQ4?|Y|P>VjQRTWRBOyNM?zo-z7YHpxCs0< z_g0@s5#fFZaSJOo_ABAx@T05$IjsHMINJQ}USHc`5yqajxU2+ z??a&Yc@!+bC&2^3tt?LCTn?(d9XtW7f$H}rP~*Q1JQjQ(cq({5cpCU0pw<^0?x zY9BWE@)-DH$}uSZ-vAH%y_-Ro5T|#5Ey9zuVtblK#g+|_&)FoQ2agxYTl(NM*yw{HP6+c__!9-JUc*^WUdD_&K;oSau>)D z=A$4}nlFOC2R;s71s;hKs$BxAU+&A-dAt$Sd^dxd=iOiiz8`!Uc-TwbI)*@vbDA%Y zfMb-`f?Dq#;2Q7=@FwtObY2dA7?d7A0#?8U$Du3WDsUBeJ9rBCRd5;jD^Pqa3EVzc zK=F4fcpkV0Tn*j=YTaK3C717jsHXWjD7`rRc*pl5P~)8dYX46H_5BP`a^Cc9F)Aj=f6MY>wgJKj?a0y)${>p{umCSQJwFTWGi zdfp4F|J@#Ufg1nwpw>MHYMw_x&HpWr-vK4R?}OTp1sJR3ya<$ESORMN(?R*ojiAQ4 z0+jr(1{Z)CsBx!2&HH*#^S&8W`#b#iJ3+1IZcyv_q%YqGs^8~8jXUeVe;X7Z|K#ic z6Vy5nI?;`PI4FK!;>$~Y`7}`DuL0Hmd{F#t1+_m{gPJb_4+IlmpM%o3*MZ{m&7j7) z6+95U1602|LGkqwP;%J~9teH~RKJHn&HE^*^*jk`+#iFI%K?jB`@_IzQGNlaen*4i z^Ch6>T>@(S3b^+GW6lM~DIdJVjT?j7w?6>oM{WmERdX+RAoxx29Plv^*I-_>)bVjD z7*JjZ%HP(&7hn(d2TLfynlfVSr07~BXfm-igkSWcRp!~tXC%d?IEU59; zfEw=-Q1jG4@zDa$0)$#!6U#Yz-NO$0OhxT3W}dYS2{T!18U!n0|Rgb909KauK;fc)&EDJ#{Dl}UO-Th zz8(r{KaT*_?nLl9a5*Twz6aDgzYa?7kAYgpli(Wg``|{fLU5Aacfj|9_k)PSTym;0 zXM#6?Ol|gnP4I^x|IAe+A?kN4$kv;OLGk(DpyoS-Ag%ch1GS!)g6cN~B0}>CQ2YHj z$X1zyPy+Qo1=M=Z0X5Efpyat3lwQ3CJQAD)j{;{v$?@&}`#qq>`HU}r!Q)rJ!>NA+ zl-#}pYM!6^@~`~&=VN@@r{g_VK(#*;l-w@{CD$=f{A~AF2gUDeJx+tqp?n=EySW)u z`?rDO?+#G&db=- zYTd_y;(r*_xTk{JpL4)tz>7f1aT1igZv-XhcY#NPANA!2K>6W^LCOD7P~(0V6dykT zweDYlTF-$fwfH>}d_H&#sP&u#ijPx3^*`I!uLG5rT?ndQ1JpRL1vTIGpyqiusPXOs z?S6w=&lkWKf!_eNzyA)Z{SQ6<($^n?a%=u0K($*0ijNaO+4E9R^Irgp-%CKP>q=1V zYM|zeLCI?esP?yjYX5dn{JjS}7Q6@4e0x1U3~HRmLCycqp!$Co)OvmhYMfty(!T{H zg$IBEM3wnF=x?ApBs*sN%_Q_^(6^yKfy!r^m(M{DL*g}q#-UF^DI;3X{bOQ7&NIpZ4bo5&2ROlXPEA&T@p2r+m{eB_u7x;1;{4z8P{jIOV zUD)RieqRlp54{|E7o_JZ=pUeaRp2=hQoOrF1)k;5u%I16u6sKI!p&;E~X2&@H}h71)68hE_xGhQ0)y z4b4G+4qXgg3cUx?(}C`@Z^qmJ)}Wi9!=aZ#dX9x&1N}9060`u)^I_;<`$k*>UjaSj z%iF-E(3QUYT5zF%e|?KF>zI3+J! zQ>%%nAJ5`wB8YZWqpV#7d8gG1vv?*>CWE3LF;P;mv>=_J80SGdoQ!PmAWTvkWUxCG zW#efcZFftz!&d8Yvt}FHVk@e}q3083s>on6&ARrR_==0DWea)KjH)am_)R_LjWB_v z%$jCX)Z-RL;{@gy7x83itIvE8PXv?kR3sU6YH@1TMiXfknYD2e!qM7Jvk`RK%`}v3 zuH3Z6ay??!h1EJ^UApx`UXyCn6d-}12FFF@RtoSl7&9DfXQJ5py zBnq4)C51{kE*qCkYXQM@T-1YFJTVd3zS`}e=(eL^X;{#MO+z64<{>+hHf!6X9a0qA zSyhPHRV`x%FaCA)Fqw>k#kuis8m`G#vo38m!!~ReS)@`j5oZW7oxfbK8(zQ>`)xTy z$5?M3gqOtfyjVJj~gVc4xd9=XLbetan?{)1mpAxxL-&WMOkzPP@FC#chowy^dSxv{{e6 zYCk(kEz0sDOwhq}N@frzd69Lh&Tcl;*hu)zq}=#j6OeyHnT=c3#I^Y@KFmwJ$dpvl?#($TZ9*qe4EW60D67ljN)+s?83T zg7W8emWSt%kjA6QIMH_FiSbpgGU62>I%g9G%@o^n1CGhgLYzpoz}|2;c95jMI*me% zl7r8es1FMed)5h=E$cT1wY1t%oHJW!6WHja9U+3G(`+@qCaI;l9KV+3 zFzho8K|kvypJ5Ogi`hCl8calNW%-hut&#O$Rp%~CCwWfbqPPt__7ehT%d`wO1aX$Z z(>lo2c#$-jJbUrtr8%Ci8g0+m!8F0lRuB7c@|wMnJzOU7{hwZD55c=QJ7H?CFn1Eh$Xb* z8RyqWZTRoy2R3nOx0~G&Iw>)*8HJPub@%Q8%ftVR7c?&OYm!FcIv@Q)RRA8^G)qIIJ+FZ6S6wNUup>VoGty{7MHbF=+H&xGiNlVn@huH4||} zSb>W&B<9jvEiWeWk@eNWZY5X~cyssB#5prNSDLUyCY*}%cpR0&A!*9GvKFgCp^{Qt zm!S35oA}AJ4ra!?+61YIoN8She}h~dM;Rt%q|-Rh*x03wJ~j^Y(Atz6$vKO&$tYog zvXQ?2BB<0)(6=NaMw~Px!%#+0bXX;0Od*(*-&&L|58_Hx842n|(Hi1lCbhGujotJW#>WO?L@z1xY&~O_M%0}qL|gkW z``DDhsUK@-rdXoizfeRf(#N@pMNJj^hX`W*ZKqmL^LI%!HVx=1HWSNBKxQ%35)*IA)EOqmg1a zd*;HKDGwc-$!z905t8xONX+tmKOse&p09W3zhJO6sijs-=47NKOlVO>9WWDAA}HjS zL!2yWx|$5Wm#*OH>KJMY#zGmufM3W>HMF@6Xq^}dS^3&EWopDrQoxclv^B3lV|S`3 z(Yc6ziGz>Yw7WQ^dSSe$aR~buFCLhm& zW|;`%?u|}O))uM;Yvj;PP*KWe^I9F4<(ce{-%FKqDr_#uc{5H-c`;$|4@1;549Z=q zf*;+1%f;R z+Q>dUQqk;88j=X*peFCOv{}q$S6fKEjQ!1lNq)+sb@|fcX5R|6#U^dQalZixcK^+% zmd#EpF$0!IQao5>6zOEAZLHsRzt+9G*Bo%+%VwuTTK<+S)nbM=)rKx}nf6GqF^ZFQ zn@1OJjpU4mHs_OZZD?(0G9MaCdtqRbD~iszjQ|t0ueS2x67h7MC||hc;;|unkVk|= z>#@<1VAYD1rwpxJF|_KmVCBk@m8(u(v1-K%8V-?1!rIfdTXDw7%F|9>!L#r}>||)n z-wCAINU)jPka~&@#yVMp%Y$I) zKsd7^jVGcVb~&Vr5=lPX?yaaa)!`x=Ubb-arp+7r(pp(rv2dN!vY|2LKVsEr*edy% z$|y2I%UPF>Z5%qi-%g9*a%X5mQpNOi20wi~E_%E&Mz(N^y}TIOh;zwDg2dfr>6wn!?U~Rc5+Q2=0>C0yIDO~t@|{G+n~`O%{Cqw z-E~frEHq=Yds?%53?>&hNt21ERQQE9*dNDVjpVQvO_8XwzPVjof{fxtXKyDlDK9U_ zQj~$Z9zEWC0#g4AgnyB$L)&Q7-kLl^Bc}OGI}f>ypTjzwlh0H@bI^kvwLO~ zH^{KUnO4Y6Nd}7?3zr3IKKM0kg)=M&0nGIFiVHpTfewvk+)z3+Mv(7{3s+yn+z`+0 z46CXN5n$n#+>N#97D_^Z2)j-7NzCk>1Yl)@HC8H>%@{OwH<^w3I}o6mwU8}=9qBBI zw%U^xNFST6u%Q9sgj?WnhR=SqX2e}pshqPniJlkFAcph!C_6H1lF+)3{TOp>SkEC> z&`le(Bg0^GjCCSX0Swc+l5sI6w@6DlvAsK^27f{ER#}TH<~(Z?T#YArXC}n6pvjUP z*AupGYry8+dRouYihBB+q>MlG^|&4!8t+KrsGk*@4L41yePvzHptFMi?ChqpJ6L# z#pQLXqG9>PdUR>5U5C^-)*cVsjQ;wo)B+0{^tc0^kQW#2`(LL9gkG;p+6#q|k`rP` z+?>y7@C=+{v;Fn-6qjWda>@X?N1P({kI(#KlFIWJJ^B?J$d;OiL}c zx3BV{Rg}gmzB3{lmrx4-7Zf`WUU)_hmq^Fo6IuEUUN&Q+@D_PUnC!?D2M57h6PK|W zPNlPZWYOigh}WCO1wO%v4q$yJs}WwyPW^bXZ{ns<;_@~w zU{Q(EH%5CD9ylVsRlhNsTb8!}5 zYcFN7D4RgId}kQ zafaiDGdwCs2y9y+z2^CA9TK0RkXxoFnQFW1XO)yKQ0DZG|JBNYudFlCd^j zxZ>o{u|dX#S`u$E^X`^HA!t1UU`T`Q03u2Tr}ubcu^3rUoKdKf8n- zw^q>GhdcpW>o}a(D+%k!j*V?{qipYO%a~-3eEatg>Ty@sw)jdHTAg~>Acbm>A9JrA zR>Oupk+nf8p^P2=66k*S0`a|jZOaX!9^!0Nw89r=Hc$Rq0;e^ z@YKuyeddZWk&Lo-yGky13C^5?Y?e&o+>f8uy~%0vKWb#`a(PO22Ge1w{$j3wVSS&Z zn6y0P3Yp8y!S=tVF?zw?&TBb;WO)deY!8fU?}!oaRBT`X7nB*RvIa}HSH${zn2jPG zA0tfp;-f1rXWuF%Z?WmAYiP4Sl6&i^_@=?#pk<&@W%+K(+|iI273>4Y8QrRO_9??F z>vevwQDW(xly&v$inwh#Dp0%$1lk}sX1VUf#eXvB3={~F=xAJz4d<=c^fld-Zqbz6 zTwW%VE+(dzUi&xJh)LihO_>>MjfAZJDaZOrV}DUQ;(H#KrL>Da`U2ehdhL$CUv>ux z`>S#LzM`g^Z+}f7eQ>);?qqOzgN|_EcG+epTm$zmJalH9Uo3YI7N7ou74X0(w>$Q( zxi3REF4xZloB>y$6_i3H`7AdetPQM767mNO1vsNWYBgN|U};z)L4;$n4h6l#g0cSE z{mxSiTQ6zO?oqz2Gni$7i)eQZrH!(OKpPMeZZZasi48Zqac-n!*O$1vLucn#x|r+R zQy?Z=B{OxxWvRgf?-Iy3|6K`>t`j?Rb4g9|g=JtSF7e}t&Yxwyan38avro%-)L^8T zdv|sc(@?fI8nwn#-IaKk+5o)F7a1|VPrVi_P-0b*t#)&XJ=umIv|KuJp=4N?OGlkHWFRk#BDLv)>s zQWHxu^Ye6F5=&C86pRcEjdTqxbPdfE3@xk-%_r|umF5A8nCTjtDi~N;8BKnw+Rx*Y vn3rCfm=085QZ%_(Em|cYr?eV4Y(Kp_dqCD diff --git a/feincms/locale/tr/LC_MESSAGES/django.po b/feincms/locale/tr/LC_MESSAGES/django.po index 7134c780b..52b458529 100644 --- a/feincms/locale/tr/LC_MESSAGES/django.po +++ b/feincms/locale/tr/LC_MESSAGES/django.po @@ -1,979 +1,967 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: +# byzgl , 2013 +# byzgl , 2013 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz \n" -"Language-Team: Turkish (http://www.transifex.com/projects/p/feincms/language/" -"tr/)\n" -"Language: tr\n" +"Language-Team: Turkish (http://www.transifex.com/projects/p/feincms/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0\n" +"Language: tr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" -msgstr "" +msgstr "tema" -#: models.py:551 +#: models.py:510 msgid "ordering" -msgstr "" +msgstr "sıralama" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" -msgstr "" +msgstr "dil" #: admin/filterspecs.py:35 admin/filterspecs.py:70 msgid "All" -msgstr "" +msgstr "Tümü" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" -msgstr "" +msgstr "Üst Öğe" #: admin/filterspecs.py:81 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" -msgstr "" +msgstr "Kategori" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" -msgstr "" +msgstr "Değişiklik %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" -msgstr "" +msgstr "başlık" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." -msgstr "" +msgstr "%s yeni bir pozisyona taşındı." -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." -msgstr "" +msgstr "Taşıma yönergeleri anlaşılamadı." -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" -msgstr "" +msgstr "olaylar" -#: admin/tree_editor.py:429 +#: admin/tree_editor.py:432 #, python-format msgid "Successfully deleted %s items." -msgstr "" +msgstr "%s öğeleri başarıyla silindi." -#: admin/tree_editor.py:437 +#: admin/tree_editor.py:440 #, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "" +msgstr "%(verbose_name_plural)s seçilenleri sil" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" -msgstr "" +msgstr "uygulama içeriği" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" -msgstr "" +msgstr "uygulama içerikleri" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" -msgstr "" +msgstr "uygulama" #: content/comments/models.py:24 msgid "enabled" -msgstr "" +msgstr "etkin" #: content/comments/models.py:24 msgid "New comments may be added" -msgstr "" +msgstr "Yeni yorumlar eklenebilir" #: content/comments/models.py:28 content/comments/models.py:29 msgid "comments" -msgstr "" +msgstr "yorumlar" #: content/comments/models.py:49 msgid "public" -msgstr "" +msgstr "genel" #: content/comments/models.py:49 msgid "not public" -msgstr "" +msgstr "genel değil" #: content/contactform/models.py:18 msgid "name" -msgstr "" +msgstr "ad" #: content/contactform/models.py:19 msgid "email" -msgstr "" +msgstr "email" #: content/contactform/models.py:20 msgid "subject" -msgstr "" +msgstr "konu" #: content/contactform/models.py:23 content/raw/models.py:14 msgid "content" -msgstr "" +msgstr "içerik" #: content/contactform/models.py:34 msgid "contact form" -msgstr "" +msgstr "iletişim formu" #: content/contactform/models.py:35 msgid "contact forms" -msgstr "" +msgstr "iletişim formları" #: content/file/models.py:20 content/file/models.py:25 #: module/medialibrary/models.py:84 msgid "file" -msgstr "" +msgstr "dosya" #: content/file/models.py:26 msgid "files" -msgstr "" +msgstr "dosyalar" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" -msgstr "" +msgstr "resim" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" -msgstr "" +msgstr "alternatif yazı" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" -msgstr "" +msgstr "Resim açıklaması" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" -msgstr "" +msgstr "altyazı" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" -msgstr "" +msgstr "resimler" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" -msgstr "" +msgstr "pozisyon" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" -msgstr "" - -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "" +msgstr "format" -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" -msgstr "" +msgstr "medya dosyası" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" -msgstr "" - -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "" +msgstr "medya dosyaları" -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" -msgstr "" +msgstr "tür" #: content/raw/models.py:18 msgid "raw content" -msgstr "" +msgstr "ham içerik" #: content/raw/models.py:19 msgid "raw contents" -msgstr "" +msgstr "ham içerikler" #: content/richtext/models.py:22 msgid "HTML Tidy" -msgstr "" +msgstr "HTML Toparla" #: content/richtext/models.py:23 msgid "Ignore the HTML validation warnings" -msgstr "" +msgstr "HTML doğrulama uyarılarını yoksay" #: content/richtext/models.py:47 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" +msgstr "HTML doğrulama işlemi %(count)d uyarı. Devam etmeden önce aşağıdaki güncellenen içeriği gözden geçirin: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" -msgstr "" +msgstr "yazı" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" -msgstr "" +msgstr "zengin yazı" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" -msgstr "" +msgstr "zengin yazı" #: content/rss/models.py:21 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "" +msgstr "Rss alanı günde birkaç kez güncellenir. Başlıktaki bir değişiklik sadece bir sonraki besleme güncellemesinden sonra ana sayfasında görülebilir." #: content/rss/models.py:22 msgid "link" -msgstr "" +msgstr "link" #: content/rss/models.py:23 msgid "pre-rendered content" -msgstr "" +msgstr "önden görüntülenen içerik" #: content/rss/models.py:24 msgid "last updated" -msgstr "" +msgstr "son güncelleme" #: content/rss/models.py:25 msgid "max. items" -msgstr "" +msgstr "max. öğe" #: content/rss/models.py:29 msgid "RSS feed" -msgstr "" +msgstr "RSS besleme" #: content/rss/models.py:30 msgid "RSS feeds" -msgstr "" +msgstr "RSS beslemeler" #: content/section/models.py:41 msgid "section" -msgstr "" +msgstr "bölüm" #: content/section/models.py:42 msgid "sections" -msgstr "" +msgstr "bölümler" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" -msgstr "" +msgstr "düz" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" -msgstr "" +msgstr "başlık satırı" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" -msgstr "" +msgstr "başlık satır ve sütunu" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" -msgstr "" +msgstr "tablo" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" -msgstr "" +msgstr "tablolar" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" -msgstr "" +msgstr "veri" #: content/template/models.py:51 msgid "template content" -msgstr "" +msgstr "tema içeriği" #: content/template/models.py:52 msgid "template contents" -msgstr "" +msgstr "tema içerikleri" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" -msgstr "" +msgstr "video linki" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "Bu, bir youtube veya vimeo video bir bağlantı olmalıdır, ör: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" -msgstr "" +msgstr "video" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" -msgstr "" +msgstr "vidyolar" #: contrib/tagging.py:117 msgid "Tagging" -msgstr "" +msgstr "Etiketleme" #: module/blog/models.py:28 msgid "published" -msgstr "" +msgstr "yayınlandı" #: module/blog/models.py:30 msgid "This is used for the generated navigation too." -msgstr "" +msgstr "Bu da oluşturulan navigasyon için kullanılır." #: module/blog/models.py:33 msgid "published on" -msgstr "" +msgstr "yayınlanan tarih" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" +msgid "" +"Will be set automatically once you tick the `published` checkbox above." +msgstr "Yukarıdaki `yayınlanan` onay kutusunu bir kez işaretleyin otomatik olarak ayarlanır." #: module/blog/models.py:39 msgid "entry" -msgstr "" +msgstr "giriş" #: module/blog/models.py:40 msgid "entries" -msgstr "" +msgstr "girişler" #: module/blog/extensions/tags.py:12 msgid "tags" -msgstr "" +msgstr "etiketler" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" -msgstr "" +msgstr "tercümesi" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." -msgstr "" +msgstr "Ana dilde girişler için boş bırakın." #: module/blog/extensions/translations.py:44 #: templates/admin/feincms/item_editor.html:43 msgid "available translations" -msgstr "" +msgstr "kullanılabilir çeviriler" #: module/extensions/changedate.py:32 msgid "creation date" -msgstr "" +msgstr "oluşturulma tarihi" #: module/extensions/changedate.py:33 msgid "modification date" -msgstr "" +msgstr "düzenlenme tarihi" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" -msgstr "" +msgstr "içerik tipleri" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" -msgstr "" +msgstr "yayın tarihi" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" -msgstr "" +msgstr "yayın bitiş tarihi" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." -msgstr "" +msgstr "Giriş sonsuza kadar aktif kalmalı ise boş bırakın." -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" -msgstr "" +msgstr "için - görünür " -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" -msgstr "" +msgstr "Tarih-bazlı yayınlama" #: module/extensions/featured.py:9 msgid "featured" -msgstr "" +msgstr "öne çıkan" #: module/extensions/featured.py:14 msgid "Featured" -msgstr "" +msgstr "Öne çıkan" #: module/extensions/seo.py:9 msgid "meta keywords" -msgstr "" +msgstr "meta anahtar kelimeler" #: module/extensions/seo.py:10 msgid "This will be prepended to the default keyword list." -msgstr "" +msgstr "Bu, varsayılan anahtar kelime listesine başına eklenecektir." #: module/extensions/seo.py:11 msgid "meta description" -msgstr "" +msgstr "meta açıklaması" #: module/extensions/seo.py:12 msgid "This will be prepended to the default description." -msgstr "" +msgstr "Bu varsayılan açıklamanın başına eklenecektir." -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" -msgstr "" +msgstr "Arama motoru optimizasyonu" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" -msgstr "" +msgstr "Çeviriyi düzemle" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" -msgstr "" +msgstr "Çeviri oluştur" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" -msgstr "" +msgstr "çeviriler" #: module/medialibrary/forms.py:26 msgid "This would create a loop in the hierarchy" -msgstr "" +msgstr "Bu hiyerarşi içinde bir döngü yaratacak" #: module/medialibrary/forms.py:64 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "" +msgstr "Farklı dosya türü (%(old_ext)s ile bir %(new_ext)s üzerine yazma girişimi) ile üzerine yazamazsınız" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" +msgstr[0] "%(count)d medya dosyaları %(category)s e başarıyla eklendi." +msgstr[1] "%(count)d medya dosyaları %(category)s e başarıyla eklendi." -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" -msgstr "" +msgstr "Seçilen medya dosyalarını kategoriye ekle" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" -msgstr "" +msgstr "ZIP dosyası %s olarak dışa aktarıldı" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" -msgstr "" +msgstr "ZIP dosyasını %s olarak dışa aktarmada hata" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" -msgstr "" +msgstr "Seçilen medya dosyalarını ZIP dosyası olarak dışa aktar" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" -msgstr "" +msgstr "Önizleme" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" -msgstr "" +msgstr "dosya boyutu" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" -msgstr "" +msgstr "oluşturuldu" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" -msgstr "" +msgstr "dosya tipi" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" -msgstr "" +msgstr "dosya bilgisi" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" -msgstr "" +msgstr "%d dosya içe aktarıldı" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" -msgstr "" +msgstr "ZIP dosyasını %s olarak içe aktarmada hata" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" -msgstr "" +msgstr "Dosya girdisi yok" #: module/medialibrary/models.py:43 msgid "parent" -msgstr "" +msgstr "üst öğe" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" -msgstr "" +msgstr "kurşun" #: module/medialibrary/models.py:49 msgid "category" -msgstr "" +msgstr "kategori" #: module/medialibrary/models.py:50 module/medialibrary/models.py:90 msgid "categories" -msgstr "" +msgstr "kategoriler" #: module/medialibrary/models.py:87 msgid "copyright" -msgstr "" +msgstr "telif hakkı" #: module/medialibrary/models.py:202 msgid "Image" -msgstr "" +msgstr "resim" #: module/medialibrary/models.py:203 msgid "Video" -msgstr "" +msgstr "Video" #: module/medialibrary/models.py:204 msgid "Audio" -msgstr "" +msgstr "Ses" #: module/medialibrary/models.py:205 msgid "PDF document" -msgstr "" +msgstr "PDF dökümanı" #: module/medialibrary/models.py:206 msgid "Flash" -msgstr "" +msgstr "Flash" #: module/medialibrary/models.py:207 msgid "Text" -msgstr "" +msgstr "Yazı" #: module/medialibrary/models.py:208 msgid "Rich Text" -msgstr "" +msgstr "Zengin Yazı" #: module/medialibrary/models.py:209 msgid "Zip archive" -msgstr "" +msgstr "Zip arşivi" #: module/medialibrary/models.py:210 msgid "Microsoft Word" -msgstr "" +msgstr "Microsoft Word" #: module/medialibrary/models.py:211 msgid "Microsoft Excel" -msgstr "" +msgstr "Microsoft Excel" #: module/medialibrary/models.py:212 msgid "Microsoft PowerPoint" -msgstr "" +msgstr "Microsoft PowerPoint" #: module/medialibrary/models.py:213 msgid "Binary" -msgstr "" +msgstr "Binary" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" -msgstr "" +msgstr "açıklama" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" -msgstr "" +msgstr "medya dosyası çevirisi" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" -msgstr "" +msgstr "medya dosyası çevirileri" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." -msgstr "" +msgstr "Bu URL aktif bir sayfa tarafından alınmış." -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." -msgstr "" +msgstr "Bu URL zaten başka aktif bir sayfa tarafından alınmış." #: module/page/modeladmins.py:41 msgid "Other options" -msgstr "" +msgstr "Diğer seçenekler" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" -msgstr "" +msgstr "navigasyonda" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" -msgstr "" +msgstr "Alt sayfa ekle" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" +msgstr "Sitede göster" + +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." -msgstr "" +msgstr "Orijinal çeviri içeriği yeni oluşturulan sayfaya kopyalandı." -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" -msgstr "" +msgstr "Bu nesneye düzenlemek için gerekli izinleriniz yok" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" -msgstr "" +msgstr "devralındı" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" -msgstr "" +msgstr "bileşenler" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" -msgstr "" +msgstr "aktif" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" -msgstr "" +msgstr "aktif" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" -msgstr "" +msgstr "URL geçersiz" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "Hedef URL geçersiz Yerel bir URL ise başında ve sonunda bölü eklemeyi unutmayın. Bu navigasyon ve alt sayfaları etkiler." -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" -msgstr "" +msgstr "buraya yönlendiriliyor" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" -msgstr "" +msgstr "Önbelleklenmiş URL" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" -msgstr "" +msgstr "sayfa" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" -msgstr "" +msgstr "sayfalar" #: module/page/extensions/excerpt.py:9 msgid "excerpt" -msgstr "" +msgstr "alıntı" #: module/page/extensions/excerpt.py:10 msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" +msgstr "Bu sayfanın içeriğini özetleyen kısa bir alıntı ekleyin." #: module/page/extensions/excerpt.py:12 msgid "Excerpt" -msgstr "" +msgstr "Alıntı" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" -msgstr "" +msgstr "navigasyon bileşeni" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." -msgstr "" +msgstr "Navigasyonu özelleştirmeniz gerekiyorsa, bu altsayfaları sağlayan modülü seçiniz." -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" -msgstr "" +msgstr "Navigasyon bileşeni" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." -msgstr "" +msgstr "İlişkili içerik olarak listelenecek sayfaları seçiniz" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" -msgstr "" +msgstr "İlgili sayfalar" #: module/page/extensions/sites.py:16 msgid "Site" -msgstr "" +msgstr "Site" #: module/page/extensions/symlinks.py:15 msgid "symlinked page" -msgstr "" +msgstr "Sembolik olarak bağlanmış sayfa" #: module/page/extensions/symlinks.py:16 msgid "All content is inherited from this page if given." -msgstr "" +msgstr "Verilirse tüm içerik bu sayfadan devralınır." #: module/page/extensions/titles.py:13 msgid "content title" -msgstr "" +msgstr "içerik başlığı" #: module/page/extensions/titles.py:14 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" +msgstr "İlk satır ana başlık, aşağıdaki satırlar ise alt başlıktır." #: module/page/extensions/titles.py:15 msgid "page title" -msgstr "" +msgstr "sayfa başlığı" #: module/page/extensions/titles.py:16 msgid "Page title for browser window. Same as title by default." -msgstr "" +msgstr "Tarayıcı penceresi için sayfa başlığı. Varsayılan olarak başlık ile aynı." #: module/page/extensions/titles.py:43 msgid "Titles" -msgstr "" +msgstr "Başlıklar" #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " -msgstr "" - -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "" +msgstr "%(filter_title)s ile" #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" -msgstr "" +msgstr "Gerçekten öğe silisin mi?" #: templates/admin/feincms/_messages_js.html:4 msgid "Confirm to delete item" -msgstr "" +msgstr "Öğeyi silmeyi onaylayın" #: templates/admin/feincms/_messages_js.html:5 msgid "Item deleted successfully." -msgstr "" +msgstr "öğe başarılı bir şekilde silindi." #: templates/admin/feincms/_messages_js.html:5 msgid "Cannot delete item" -msgstr "" +msgstr "Öğe silinemiyor" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "" +msgstr "öğe silinemiyor, çünkü en az bir alt öğeye sahip." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" -msgstr "" +msgstr "Temayı değiştir" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template?
All changes are saved." -msgstr "" +msgstr "Tema değiştirilsin mi?
Tüm değişiklikler kaydedildi." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." -msgstr "" +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." +msgstr "Gerçekten tema değişsin mi?
Tüm değişiklikler kaydedildi ve %%(source_regions)s teki içerikler %%(target_region)s e taşındı." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" -msgstr "" +msgstr "Gizle" #: templates/admin/feincms/_messages_js.html:13 msgid "Show" -msgstr "" +msgstr "Göster" #: templates/admin/feincms/_messages_js.html:14 msgid "After" -msgstr "" +msgstr "Sonra" #: templates/admin/feincms/_messages_js.html:15 msgid "Before" -msgstr "" +msgstr "Önce" #: templates/admin/feincms/_messages_js.html:16 msgid "Insert new:" +msgstr "Yeni ekle:" + +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" msgstr "" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" -msgstr "" +msgstr "Bölge boş" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "" +msgstr "Üst siteden içerik otomatik devralınır. Bu davranışı geçersiz kılmak için, bazı içerikler ekleyin." -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" -msgstr "" +msgstr "Yeni öğe ekle" #: templates/admin/feincms/content_inline.html:91 #, python-format msgid "Add another %(verbose_name)s" -msgstr "" +msgstr "Başka ekle %(verbose_name)s" #: templates/admin/feincms/content_inline.html:94 msgid "Remove" -msgstr "" +msgstr "Kaldır" #: templates/admin/feincms/fe_editor.html:40 msgid "Save" -msgstr "" +msgstr "Kaydet" #: templates/admin/feincms/fe_tools.html:28 msgid "Stop Editing" -msgstr "" +msgstr "Düzenlemeyi Durdur" #: templates/admin/feincms/fe_tools.html:33 msgid "edit" -msgstr "" +msgstr "düzenle" #: templates/admin/feincms/fe_tools.html:35 msgid "new" -msgstr "" +msgstr "yeni" #: templates/admin/feincms/fe_tools.html:36 msgid "up" -msgstr "" +msgstr "yukarı" #: templates/admin/feincms/fe_tools.html:37 msgid "down" -msgstr "" +msgstr "aşağı" #: templates/admin/feincms/fe_tools.html:38 msgid "remove" -msgstr "" +msgstr "kaldır" #: templates/admin/feincms/recover_form.html:8 #: templates/admin/feincms/revision_form.html:8 #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 msgid "Home" -msgstr "" +msgstr "Anasayfa" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Sşilineni kurtar %(verbose_name)s" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Nesnenin bu sürümünü kurtarmak için aşağıdaki kaydet düğmesine basın." #: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "" +msgstr "Geçmiş" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Dön %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Nesnenin bu sürümüne dönmek için aşağıdaki kaydet düğmesine basın." #: templates/admin/feincms/tree_editor.html:32 msgid "Shortcuts" -msgstr "" +msgstr "Kısayollar" #: templates/admin/feincms/tree_editor.html:34 msgid "Collapse tree" -msgstr "" +msgstr "Ağacı daralt" #: templates/admin/feincms/tree_editor.html:35 msgid "Expand tree" -msgstr "" +msgstr "Ağacı genişlet" #: templates/admin/feincms/tree_editor.html:38 msgid "Filter" -msgstr "" +msgstr "Filtre" #: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" -msgstr "" +msgstr "Sitede düzenle" #: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "" +msgstr "Ekle" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "" +msgstr "Kategoriye medya dosyaları ekle" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "" +msgstr "Uygulamak için kategori seçin:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" +msgstr "Aşağıdaki ortam dosyaları seçilen kategoriye eklenecektir:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "" +msgstr "Kategoriye ekle" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "İptal" #: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" -msgstr "" +msgstr "Toplu upload ZIP dosyası:" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "" +msgstr "Üzerine yaz" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" -msgstr "" +msgstr "Gönder" #: templates/content/comments/default.html:10 #, python-format msgid "%(comment_count)s comments." -msgstr "" +msgstr "%(comment_count)s yorum" #: templates/content/comments/default.html:18 #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " -msgstr "" +msgstr "\n %(comment_username)s dedi buna %(comment_submit_date)s
\n " #: templates/content/comments/default.html:28 msgid "No comments." -msgstr "" +msgstr "Yorum yok." #: templates/content/comments/default.html:36 msgid "Post Comment" -msgstr "" +msgstr "Yorum gönder" #: templates/content/contactform/form.html:9 msgid "Submit" -msgstr "" +msgstr "Gönder" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" -msgstr "" +msgstr "Teşekkürler!" diff --git a/feincms/locale/zh_CN/LC_MESSAGES/django.mo b/feincms/locale/zh_CN/LC_MESSAGES/django.mo index 43903981b75d5b4f79bb07005721d07e3809a42a..55ed1a58ec8b18d32c101a0feeddc2b06358eb52 100644 GIT binary patch delta 4663 zcmX}v3w+Jz9mnzKAVC__tbUL(j_iMTbHRE5lL1_EIBEn>%oe(qPIiQ z4lylO6VubJZe?wa+OX;9_Ude}nd*z_Ue66?Y?l?l>Qr_#w8(+c+HW zpvD`X=-l1-FzUDp)X*!C_P~6o!<43SB?Hbg|*JC_x$By_0 z-i3!y6P-XU^f#yz`VckoMGW94*a2sAIXg1HE2E;0D$Kwd)PXOc2HuD%xB~~_Q5=k) zqt2v1t7l9%9CfKDS$hulpk0qzcr$WtZZmely%^j|<*@BAi|aXzb|vZzT2Ke>!f)c6 zs7v}E)R~Xy?wxTl>I^5M7WfEiqGn9P7SuTJpe8!^aRDjkED_)P5hJj{Ci}FPWd9CcKWC=oZ%F9ot^d;5vcDDO`V@QIL+YcpO(@ zG>>XFHlrTGgP4ogu^dx)vXw119z*#2jByvLg`9(9R(qV~_S_CRwi>WWRa?ZKJ0 z!H>G6b*P6fVD07RD%6=hgOQb+o2rf3u3QP~8JmYXu_n~lcQr=7{~M|BvU0DX z26_v1>5rgZMCVWgUqDU#7u3YpQ2XDs?YB`U5}oFqKrE`AggUMVYTR_x2@b{hAeB*6 zv|%#pOy{E}s70-KnYGtgdp&A^7S#T`Pz&6Tx-~~o6COt`@C>T|1JwKBBhCnxJn0q?uKpX+Q;ipMGcsaylq_}>dYtD_Nk~do{4%vEwKJAsQq5G z?XBiv^L^C&;6l(k68k#G%g^;ft$Y}2;OV9xqiNS#yV2S!Q4>9lQ5drJX7tnEfzcS% z&okCcLf%Qd_^e|nYQj-w3G(M=@R5VdQCFfBbYQ4?LjG`xzPvGV|L zyd>24X{h%=Kh*Zok$&#~15`A?6x2N~M^@&RVhO&E8sH{sfnQoXCd=zjK=pUGb|2IU zWTPfpVEv1%e=+J=*^dwD`+t=RFF7|V+j~mqpq_ys&catv59dwP!cw^(T2QGu4P$A~ z!f9BEdX^4b|9RB@m&~iye*=R$^Dn5#xLj|bbkqTP<`8qFS&W*n#GGOM71my8F17yE z<~r+NZ|&{5+<#59n~wIl&o+c@$3xaWX`VGNm>12<=HJZEPz$_eM&)_!MAUq}%)WW{ z{m-F8_iB)B7-imPmZAonX6-VJqg`n(MqR-*=F8T<7w@9~ZM+*#p~m?GY9UvG*72!z z{1>$l-DvF)gK8&OI~6rRy0!CAS8fPuzar}|MlGns+K*bh!d!ydKe*N^8&E6VhMHgx zY5@n#W2gg8n7_6DkIYNhf$dkV{dd$j|FX7^e@1D%PG+2E&~>At9ebJsP!kRHc5q{@ zJptqBpKAT{%xZHH>PjrO_A=DCE3N$;>iCz?hkeN~7it%u7(7Vz8M1}ENuDPvE#y6- z!&GWK-2J$LloI|$87b@d+-Y@vnRTxG+bmL;F;c$I=Z{Dsc|FqO+*-W@AEVJkMw3(I zyF`UIO{9Fw6z>qd6&@gmNeofZH@=c|RD<#wIYD}`qAU~DAD{b1mQ@7 zA5Sw4A0~^fEuJFVh%WToWD;p6DnBKyBtT}6)kH;4)jTqkJWd+PGV(K`a)9|GMK8_i zR{sgEAPwY6a){{d-G!)(A{!$${=0!Y$XILt9Dhml{Hy4tt|#h!Qby*JACn_wJxT7z z#~Va1&uXF)8}h{`1t0Vpkx%_x7Lf{a9~nd1%5tmp!I#MkMBfI!&5_@E{ZM6+g=7_} zB|jtyWGY!gx)PNPvYq@ucjl;iDEcLAD@&;iZflr>FvaRC&2G4tj3e>nUQ$d{>Ipxv zk+Q%%W_|~CPbTWKoXU$NinNuvR?&~tudSYr$H^RWn#?9D&yjDF2_%X1CY{Jh(pGY) zWLsmixm#)#k(%e$rN6rScY8MBXL& zVy^K#4UYVsCTRM(c*G<;=sLqlUlL(G)P({skvSNH?fb+tLg{y;@h zT48>{z?_2ooWj9r1qDR~g`w8;)bVXS`NN9}2503{VoLoDft=~}{@R9x{y<%QQQAa* zAW&89Z%8YtXb4o)R@E(RN*hu0*ceS+RZ$(tEw2j2X3PyO%a|2c>aVSA^j9)nQ`OvY ylS1b+GTPl66KYAw3T0$&3ZKmE7ajihfOuaxIr~(*@Ri&GUpOVd$rsvGaQgq=CgyGc delta 4864 zcmZYCeRLGn9mesSK!V{N%4;ZQ3E?$llMMvIix>b)Mj74e>deELDp3;7w%rE}aIXwHh_s-0{ckay2 zhU&u4iy~KA)?e$`J|I6OdlH>%ALrblCTewVYYXS5;x=rJ@hzR}fbEbb*9X(E02|{> ztcP>4KUSgoJ%CN|PpI?%jvOCxw<)NDMn7?`8D?Pu=Ak+&zyJ=n_9|qKZjreh+frYJ z4RNQn$B?ewVH}F*@D6O*%DE)$fXx`+b)le(&A~R9kJE4xs)G}#E5C$Y@jB{CThQ1X z@5Ba}iH)!yYM^}7L`R}7Xe?^ri5SL0tk3xFFBH_lCu+bN?2Ok@CpKkP>bMmqqYwMw zK+M6}sFkZm=H?EdminyK|BCIY-#|?~iREH3TpNt&%6n4SjJc=-KEz!79CZa9+j;G2 zcn|deYDvSWi625;@d?xwoeHdyf$D;0W335AK6{_PXYT_GE--2zZTe8P|6E*NL)Y6|t9Uu9~ z8a^{`pqB7Ic0hv^?}TQkCGCisP^#7aW^dF)a#0-*HVdqMl-0+fCin<4!H6rNppIvw z2Cg(C=5nmPLURLZWwxNMq#AYJe)AaW%1@)N_#&$RE9OmdbPTm!_MGepibxZtKA7J%isPo67R%jAx0!63^gfOCeRY^eu zFF?)oX;k|P)QcpFI$=Ai!=0$(UPGO?A2q?Fs1-VI`#(jUSA&|sKT#L(9jf1ksoZ~E zLHks%!>$-lJsowTA2s7XsDbZB4N!nvcYQ?P|%y~w(ZF2>K!-;bwGhR)|`rZUzAz>Rpc$}4kGU+_rA4%Wqyx|v?q4+ z`fGx!C!;15=|mxcLb^2sFi3qM>cCCr%jRz6CFk~8{Q_#De>Sfo|J>JnWMI4Q-bxgp zZqWqPy`PDk7jg5wf?JB3(Hhjx?q+L$1D8@iX8Q|z@HYbWF{lYXiJHJN?2l{l9=u@t zTlVyxq4s7P-o^e*Y{~epjDnAbg_wlfP#x|@4e%D~y>Q(2e`xKWnb%MgzJa>e@#)?K z+u;c6_oMn*i|Tiy)ptpK|6jKq2W`hm)Rmk?Jwyq;yot3&b(DhI-xc-jOvUlI4tZ<4 zf1w`Q#;m`d2|rH4;i!l871Roz!H7Eifr5e;sg(hQ=6|>Dd(3-ofgrW~Q|dGV`r{xYZvrA4R>Ai>+RY z>VLM?7nn;jS$_?*!Wvea8_ccd4paww%_HV%+ke^o*u08*mabdR+NJ_BHCnZ>{|{YC;M8`J;i_q3S7SHtP6$&C#fdPDJ%zj5@EvGvek^&K)>c`Df<~j2c>bSp|*HGhqSG%A4|6glJ%=VVPIckPJvzzHh zO)SUi{ZSp~S^WXjts94NsCU5u(u?>=-F7zxeNFW@$4Gtu>o%1?AUR|iIYr`$w);G4 zKL=QOhN+j+tK=E0&%?o1*3#>>%b%CEt2YD}km2MF646rBZIdZ%BR{i-^Qe`$K*D4y z(R<+p;X!uCNoR75G$&6JUM02vdjeNZRuHY4ww`3G3T%2s^Scvq`zhQ(eoyWtxuh#u zLLMaj$Qhy^9liDHw!IWyBz?%Q$^AsjKZ3L*4-;)AEvbdJkhV>M3P6AlL=&;?zuMo z!ZjiKtL5jUZhMTvJ9QOIA+M3~(u!MjpxI;|cN{*-pj~ zZ5uplKNs;?YV}n($;$8I(P&1C^NqWghkS*>+2PVqd5_qw7Ht~DlG@LR^93tPio?F~ z503Or3sv}nmEllXFkD*bt0*oittc)G$3n?f^%5SN6)Kz=yWVkFT)pCH;aFzM%D9Az z(vs=n*b!fwxU`02Mvu$LuPElsPVVL>Tr{s@{ev&#ldSB<%xQ5ZJ7U|J-o!2+&{>8ej zUu<3a<@WVGV*a%5iLuc=+r~A!c63k8su%w8(q49P&9UP2Gx3Qv&mOMXv@YiNXUEm6 TIanQ=lKBLM=VQ^2vd;Yv2P+5p diff --git a/feincms/locale/zh_CN/LC_MESSAGES/django.po b/feincms/locale/zh_CN/LC_MESSAGES/django.po index 6e57bf930..d732c1914 100644 --- a/feincms/locale/zh_CN/LC_MESSAGES/django.po +++ b/feincms/locale/zh_CN/LC_MESSAGES/django.po @@ -1,35 +1,34 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: -# , 2011. -# Mark Renton , 2011. +# aaffdd11 , 2011 +# indexofire , 2011 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-16 18:17+0200\n" -"PO-Revision-Date: 2012-06-15 08:25+0000\n" -"Last-Translator: aaffdd11 \n" -"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/feincms/" -"language/zh_CN/)\n" -"Language: zh_CN\n" +"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" +"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"PO-Revision-Date: 2013-10-25 09:15+0000\n" +"Last-Translator: Matthias Kestenholz \n" +"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/feincms/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0\n" +"Language: zh_CN\n" +"Plural-Forms: nplurals=1; plural=0;\n" -#: models.py:420 content/template/models.py:59 +#: models.py:370 content/template/models.py:59 msgid "template" msgstr "模板" -#: models.py:551 +#: models.py:510 msgid "ordering" msgstr "排序" #: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:119 +#: module/extensions/translations.py:123 msgid "language" msgstr "语言" @@ -37,7 +36,7 @@ msgstr "语言" msgid "All" msgstr "全部" -#: admin/filterspecs.py:46 module/page/models.py:143 +#: admin/filterspecs.py:46 module/page/models.py:172 msgid "Parent" msgstr "父级" @@ -46,50 +45,50 @@ msgstr "父级" msgid "Category" msgstr "分类" -#: admin/item_editor.py:157 +#: admin/item_editor.py:159 #, python-format msgid "Change %s" msgstr "修改 %s" -#: admin/tree_editor.py:229 content/rss/models.py:20 +#: admin/tree_editor.py:234 content/rss/models.py:20 #: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:141 -#: module/page/models.py:199 +#: module/medialibrary/models.py:40 module/page/models.py:170 +#: module/page/models.py:226 msgid "title" msgstr "标题" -#: admin/tree_editor.py:404 +#: admin/tree_editor.py:407 #, python-format msgid "%s has been moved to a new position." msgstr "%s 已被移至新的位置" -#: admin/tree_editor.py:408 +#: admin/tree_editor.py:411 msgid "Did not understand moving instruction." msgstr "无法接受的移动指令" -#: admin/tree_editor.py:417 +#: admin/tree_editor.py:420 msgid "actions" msgstr "动作" -#: admin/tree_editor.py:429 -#, fuzzy, python-format +#: admin/tree_editor.py:432 +#, python-format msgid "Successfully deleted %s items." -msgstr "真的要删除?" +msgstr "" -#: admin/tree_editor.py:437 -#, fuzzy, python-format +#: admin/tree_editor.py:440 +#, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "Recover deleted %(verbose_name)s" +msgstr "" -#: content/application/models.py:272 +#: content/application/models.py:218 msgid "application content" msgstr "应用程序内容" -#: content/application/models.py:273 +#: content/application/models.py:219 msgid "application contents" msgstr "应用程序内容" -#: content/application/models.py:298 +#: content/application/models.py:249 msgid "application" msgstr "应用程序" @@ -146,65 +145,45 @@ msgstr "文件" msgid "files" msgstr "文件" -#: content/image/models.py:43 content/image/models.py:52 +#: content/image/models.py:45 content/image/models.py:54 msgid "image" msgstr "图片" -#: content/image/models.py:46 +#: content/image/models.py:48 msgid "alternate text" msgstr "" -#: content/image/models.py:47 +#: content/image/models.py:49 msgid "Description of image" msgstr "" -#: content/image/models.py:48 module/medialibrary/models.py:235 +#: content/image/models.py:50 module/medialibrary/models.py:231 msgid "caption" msgstr "题目" -#: content/image/models.py:53 +#: content/image/models.py:55 msgid "images" msgstr "图片" -#: content/image/models.py:79 content/medialibrary/models.py:115 -#: content/medialibrary/models.py:123 +#: content/image/models.py:80 msgid "position" msgstr "位置" -#: content/image/models.py:87 +#: content/image/models.py:88 msgid "format" msgstr "" -#: content/medialibrary/models.py:48 -msgid "(no caption)" -msgstr "(无标题)" - -#: content/medialibrary/models.py:97 content/medialibrary/models.py:111 -#: content/medialibrary/models.py:121 content/medialibrary/v2.py:48 -#: content/section/models.py:36 module/medialibrary/fields.py:58 -#: module/medialibrary/models.py:97 +#: content/medialibrary/models.py:49 content/section/models.py:36 +#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 msgid "media file" msgstr "多媒体文件" -#: content/medialibrary/models.py:98 content/medialibrary/v2.py:49 -#: module/medialibrary/models.py:98 +#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 msgid "media files" msgstr "多媒体文件" -#: content/medialibrary/models.py:139 -msgid "block" -msgstr "区块" - -#: content/medialibrary/models.py:140 -msgid "left" -msgstr "左" - -#: content/medialibrary/models.py:141 -msgid "right" -msgstr "右" - -#: content/medialibrary/v2.py:53 content/section/models.py:52 -#: content/table/models.py:85 +#: content/medialibrary/models.py:58 content/section/models.py:52 +#: content/table/models.py:82 msgid "type" msgstr "类型" @@ -229,18 +208,17 @@ msgstr "忽略HTML验证错误警告" msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "" -"HTML验证产生 %(count)d 个警告。请在继续前查看下面更新的内容: %(messages)s" +msgstr "HTML验证产生 %(count)d 个警告。请在继续前查看下面更新的内容: %(messages)s" -#: content/richtext/models.py:81 content/section/models.py:35 +#: content/richtext/models.py:84 content/section/models.py:35 msgid "text" msgstr "纯文本" -#: content/richtext/models.py:85 +#: content/richtext/models.py:88 msgid "rich text" msgstr "富文本" -#: content/richtext/models.py:86 +#: content/richtext/models.py:89 msgid "rich texts" msgstr "富文本" @@ -282,27 +260,27 @@ msgstr "版块" msgid "sections" msgstr "版块" -#: content/table/models.py:66 +#: content/table/models.py:63 msgid "plain" msgstr "无格式" -#: content/table/models.py:67 +#: content/table/models.py:64 msgid "title row" msgstr "标题行" -#: content/table/models.py:69 +#: content/table/models.py:66 msgid "title row and column" msgstr "标题行和列" -#: content/table/models.py:75 +#: content/table/models.py:72 msgid "table" msgstr "表格" -#: content/table/models.py:76 +#: content/table/models.py:73 msgid "tables" msgstr "表格" -#: content/table/models.py:90 +#: content/table/models.py:87 msgid "data" msgstr "数据" @@ -314,23 +292,21 @@ msgstr "模板内容" msgid "template contents" msgstr "模板内容" -#: content/video/models.py:25 +#: content/video/models.py:31 msgid "video link" msgstr "视频链接" -#: content/video/models.py:26 +#: content/video/models.py:32 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" -msgstr "" -"请输入youtube或vimeo视频链接,比如:http://www.youtube.com/watch?" -"v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: " +"http://www.youtube.com/watch?v=zmj1rpzDRZ0" +msgstr "请输入youtube或vimeo视频链接,比如:http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:30 +#: content/video/models.py:37 msgid "video" msgstr "视频" -#: content/video/models.py:31 +#: content/video/models.py:38 msgid "videos" msgstr "视频" @@ -351,7 +327,8 @@ msgid "published on" msgstr "发布于" #: module/blog/models.py:34 -msgid "Will be set automatically once you tick the `published` checkbox above." +msgid "" +"Will be set automatically once you tick the `published` checkbox above." msgstr "一旦你将`发表`复选框以上打勾选中,日志将设置成自动发布。" #: module/blog/models.py:39 @@ -367,12 +344,12 @@ msgid "tags" msgstr "标签" #: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:122 +#: module/extensions/translations.py:126 msgid "translation of" msgstr "翻译" #: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:125 +#: module/extensions/translations.py:129 msgid "Leave this empty for entries in the primary language." msgstr "在主要语言项中对这些条目留空。" @@ -389,27 +366,27 @@ msgstr "创建日期" msgid "modification date" msgstr "修改日期" -#: module/extensions/ct_tracker.py:136 +#: module/extensions/ct_tracker.py:140 msgid "content types" msgstr "内容类型" -#: module/extensions/datepublisher.py:49 +#: module/extensions/datepublisher.py:67 msgid "publication date" msgstr "发布起始日期" -#: module/extensions/datepublisher.py:51 +#: module/extensions/datepublisher.py:70 msgid "publication end date" msgstr "发布结束日期" -#: module/extensions/datepublisher.py:53 +#: module/extensions/datepublisher.py:72 msgid "Leave empty if the entry should stay active forever." msgstr "如果条目要永久显示,请留空" -#: module/extensions/datepublisher.py:80 +#: module/extensions/datepublisher.py:103 msgid "visible from - to" msgstr "可查看日期" -#: module/extensions/datepublisher.py:90 +#: module/extensions/datepublisher.py:113 msgid "Date-based publishing" msgstr "发布基于日期控制" @@ -437,19 +414,19 @@ msgstr "meta 描述" msgid "This will be prepended to the default description." msgstr "这将作为默认的描述被添加" -#: module/extensions/seo.py:18 +#: module/extensions/seo.py:17 msgid "Search engine optimization" msgstr "搜索引擎优化" -#: module/extensions/translations.py:192 +#: module/extensions/translations.py:207 msgid "Edit translation" msgstr "编辑翻译" -#: module/extensions/translations.py:195 +#: module/extensions/translations.py:210 msgid "Create translation" msgstr "创建翻译" -#: module/extensions/translations.py:200 +#: module/extensions/translations.py:215 msgid "translations" msgstr "翻译" @@ -464,62 +441,62 @@ msgid "" "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:57 +#: module/medialibrary/modeladmins.py:58 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "Successfully added %(count)d media files to %(category)s." -#: module/medialibrary/modeladmins.py:75 +#: module/medialibrary/modeladmins.py:77 msgid "Add selected media files to category" msgstr "所选的媒体文件添加到类" -#: module/medialibrary/modeladmins.py:84 +#: module/medialibrary/modeladmins.py:86 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:88 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:91 +#: module/medialibrary/modeladmins.py:93 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:134 +#: module/medialibrary/modeladmins.py:136 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "预览" -#: module/medialibrary/modeladmins.py:139 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 msgid "file size" msgstr "文件大小" -#: module/medialibrary/modeladmins.py:144 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 msgid "created" msgstr "创建" -#: module/medialibrary/modeladmins.py:163 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 msgid "file type" msgstr "文件类型" -#: module/medialibrary/modeladmins.py:184 +#: module/medialibrary/modeladmins.py:186 msgid "file info" msgstr "文件信息" -#: module/medialibrary/modeladmins.py:196 +#: module/medialibrary/modeladmins.py:198 #, python-format msgid "%d files imported" msgstr "导入 %d 个文件" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:200 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:202 msgid "No input file given" msgstr "没有选择文件" @@ -527,7 +504,7 @@ msgstr "没有选择文件" msgid "parent" msgstr "父" -#: module/medialibrary/models.py:45 module/page/models.py:142 +#: module/medialibrary/models.py:45 module/page/models.py:171 msgid "slug" msgstr "slug" @@ -591,23 +568,23 @@ msgstr "Microsoft PowerPoint" msgid "Binary" msgstr "二进制文件" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:232 msgid "description" msgstr "描述" -#: module/medialibrary/models.py:239 +#: module/medialibrary/models.py:235 msgid "media file translation" msgstr "媒体文件翻译" -#: module/medialibrary/models.py:240 +#: module/medialibrary/models.py:236 msgid "media file translations" msgstr "媒体文件翻译" -#: module/page/forms.py:118 +#: module/page/forms.py:172 msgid "This URL is already taken by an active page." msgstr "此URL已被其他页面使用" -#: module/page/forms.py:136 +#: module/page/forms.py:190 msgid "This URL is already taken by another active page." msgstr "此URL已被另一个页面使用" @@ -615,75 +592,78 @@ msgstr "此URL已被另一个页面使用" msgid "Other options" msgstr "其他选项" -#: module/page/modeladmins.py:89 module/page/models.py:145 +#: module/page/modeladmins.py:90 module/page/models.py:174 msgid "in navigation" msgstr "导航中" -#: module/page/modeladmins.py:100 +#: module/page/modeladmins.py:105 msgid "Add child page" msgstr "增加子页面" -#: module/page/modeladmins.py:102 +#: module/page/modeladmins.py:107 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "站内查看" -#: module/page/modeladmins.py:130 +#: module/page/modeladmins.py:126 +#, python-format +msgid "Add %(language)s Translation of \"%(page)s\"" +msgstr "" + +#: module/page/modeladmins.py:156 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:144 +#: module/page/modeladmins.py:170 msgid "You don't have the necessary permissions to edit this object" msgstr "你无权编辑该对象" -#: module/page/modeladmins.py:159 +#: module/page/modeladmins.py:185 msgid "inherited" msgstr "继承" -#: module/page/modeladmins.py:163 +#: module/page/modeladmins.py:189 msgid "extensions" msgstr "扩展" -#: module/page/modeladmins.py:167 module/page/models.py:179 +#: module/page/modeladmins.py:193 module/page/models.py:206 msgid "is active" msgstr "激活" -#: module/page/models.py:138 +#: module/page/models.py:167 msgid "active" msgstr "激活" -#: module/page/models.py:146 +#: module/page/models.py:175 msgid "override URL" msgstr "URL覆盖" -#: module/page/models.py:147 +#: module/page/models.py:176 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." -msgstr "" -"覆盖目标URL,如果它是一个本地的URL,一定要包括在开始和结束时的斜线。这会影响" -"导航和子页面的URL" +"the end if it is a local URL. This affects both the navigation and subpages'" +" URLs." +msgstr "覆盖目标URL,如果它是一个本地的URL,一定要包括在开始和结束时的斜线。这会影响导航和子页面的URL" -#: module/page/models.py:148 +#: module/page/models.py:177 msgid "redirect to" msgstr "转向" -#: module/page/models.py:149 -msgid "Target URL for automatic redirects." -msgstr "转向目标URL" +#: module/page/models.py:178 +msgid "Target URL for automatic redirects or the primary key of a page." +msgstr "" -#: module/page/models.py:150 +#: module/page/models.py:180 msgid "Cached URL" msgstr "URL缓存" -#: module/page/models.py:161 +#: module/page/models.py:395 msgid "page" msgstr "页面" -#: module/page/models.py:162 +#: module/page/models.py:396 msgid "pages" msgstr "页面" @@ -699,26 +679,26 @@ msgstr "添加一条简要形容页面内容" msgid "Excerpt" msgstr "摘抄" -#: module/page/extensions/navigation.py:80 -#: module/page/extensions/navigation.py:100 +#: module/page/extensions/navigation.py:82 +#: module/page/extensions/navigation.py:107 msgid "navigation extension" msgstr "导航扩展" -#: module/page/extensions/navigation.py:102 +#: module/page/extensions/navigation.py:110 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "如果您需要定制的导航,选择提供此页面的子页面模块。" -#: module/page/extensions/navigation.py:115 +#: module/page/extensions/navigation.py:125 msgid "Navigation extension" msgstr "导航扩展" -#: module/page/extensions/relatedpages.py:13 +#: module/page/extensions/relatedpages.py:14 msgid "Select pages that should be listed as related content." msgstr "选择页面作为相关页面在列表中显示" -#: module/page/extensions/relatedpages.py:20 +#: module/page/extensions/relatedpages.py:19 msgid "Related pages" msgstr "相关页面" @@ -759,10 +739,6 @@ msgstr "标题" msgid " By %(filter_title)s " msgstr "由 %(filter_title)s" -#: templates/admin/content/mediafile/init.html:9 -msgid "Search" -msgstr "搜索" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "真的要删除?" @@ -792,13 +768,12 @@ msgid "Really change template?
All changes are saved." msgstr "真的要修改模板么?
全部修改已被保存。" #: templates/admin/feincms/_messages_js.html:9 -#, fuzzy, python-format +#, python-format msgid "" -"Really change template?
All changes are saved and content from " -"%%(source_regions)s is moved to %%(target_region)s." +"Really change template?
All changes are saved and content from " +"%%(source_regions)s is moved to " +"%%(target_region)s." msgstr "" -"真的修改模板?
所有修改已保存,%(source_regions)s的内" -"容已被移到%(target_region)s" #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -820,17 +795,21 @@ msgstr "之前" msgid "Insert new:" msgstr "插入新的" -#: templates/admin/feincms/content_editor.html:11 +#: templates/admin/feincms/content_editor.html:15 +msgid "Copy content from the original" +msgstr "" + +#: templates/admin/feincms/content_editor.html:19 msgid "Region empty" msgstr "空区域" -#: templates/admin/feincms/content_editor.html:15 +#: templates/admin/feincms/content_editor.html:25 msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." msgstr "父站的内容已自动继承。添加新内容会覆盖。" -#: templates/admin/feincms/content_editor.html:23 +#: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "新建" @@ -966,14 +945,9 @@ msgstr "%(comment_count)s 条评论" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s
\n" -" " -msgstr "" -"\n" -" %(comment_username)s 在 %(comment_submit_date)s 说
\n" +" %(comment_username)s said on %(comment_submit_date)s
\n" " " +msgstr "\n %(comment_username)s 在 %(comment_submit_date)s 说
\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -990,6 +964,3 @@ msgstr "提交" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "感谢" - -#~ msgid "Symlinked page" -#~ msgstr "链接页面" From 282a67d85d46dc290f87b80a038091785f5796db Mon Sep 17 00:00:00 2001 From: Charlie Denton Date: Fri, 25 Oct 2013 10:18:08 +0100 Subject: [PATCH 0793/1590] Use django's six instead of own compat module. --- feincms/admin/filterspecs.py | 4 ++-- feincms/contrib/tagging.py | 4 ++-- feincms/module/medialibrary/fields.py | 4 ++-- feincms/templatetags/feincms_thumbnail.py | 4 ++-- feincms/utils/compat.py | 13 ------------- feincms/utils/html/tidy.py | 13 +++++++++++-- 6 files changed, 19 insertions(+), 23 deletions(-) delete mode 100644 feincms/utils/compat.py diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index 1b20b1641..681e04b1a 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -5,12 +5,12 @@ # Guilherme M. Gondim (semente) from django.contrib.admin.filters import FieldListFilter, ChoicesFieldListFilter +from django.utils import six from django.utils.encoding import smart_text from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ from feincms.utils import shorten_string -from feincms.utils.compat import text_type class ParentFieldListFilter(ChoicesFieldListFilter): @@ -59,7 +59,7 @@ def __init__(self, f, request, params, model, model_admin, field_path=None): # Restrict results to categories which are actually in use: self.lookup_choices = [ - (i.pk, text_type(i)) for i in f.related.parent_model.objects.exclude(**{ + (i.pk, six.text_type(i)) for i in f.related.parent_model.objects.exclude(**{ f.related.var_name: None }) ] diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index f029a6b48..b3ef0aefa 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -13,12 +13,12 @@ from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple from django.db.models.signals import pre_save +from django.utils import six from django.utils.translation import ugettext_lazy as _ from tagging.fields import TagField from tagging import AlreadyRegistered -from feincms.utils.compat import text_type # ------------------------------------------------------------------------ def taglist_to_string(taglist): @@ -69,7 +69,7 @@ def _render(name, value, attrs=None, *args, **kwargs): return type(widget).render(widget, name, value, attrs, *args, **kwargs) widget.render = _render defaults['widget'] = widget - choices = [(text_type(t), text_type(t)) for t in Tag.objects.all()] + choices = [(six.text_type(t), six.text_type(t)) for t in Tag.objects.all()] return TagSelectFormField(choices=choices, required=not self.blank, **defaults) diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 71654ba07..95bcabbcd 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -7,13 +7,13 @@ from django.contrib.admin.widgets import AdminFileWidget from django.contrib.admin.widgets import ForeignKeyRawIdWidget from django.db import models +from django.utils import six from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from feincms.admin.item_editor import FeinCMSInline from feincms.utils import shorten_string -from feincms.utils.compat import text_type from .models import MediaFile from .thumbnail import admin_thumbnail @@ -31,7 +31,7 @@ def label_for_value(self, value): try: obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) label = [u' %s' % escape( - shorten_string(text_type(obj)))] + shorten_string(six.text_type(obj)))] image = admin_thumbnail(obj) if image: diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 6cfe00506..6107a8326 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -21,9 +21,9 @@ from django.utils.encoding import force_text, python_2_unicode_compatible from django.core.files.storage import default_storage from django.core.files.base import ContentFile +from django.utils import six from feincms import settings -from feincms.utils.compat import text_type register = template.Library() @@ -40,7 +40,7 @@ def __init__(self, filename, size='200x200'): @property def url(self): - return text_type(self) + return six.text_type(self) def __str__(self): match = self.THUMBNAIL_SIZE_RE.match(self.size) diff --git a/feincms/utils/compat.py b/feincms/utils/compat.py deleted file mode 100644 index 126775e3a..000000000 --- a/feincms/utils/compat.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Compatibility shims.""" -import sys - - -# Python 2/3 compatiibility. -# From http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ -PY2 = sys.version_info[0] == 2 -if not PY2: - text_type = str - unichr = chr -else: - text_type = unicode - unichr = unichr diff --git a/feincms/utils/html/tidy.py b/feincms/utils/html/tidy.py index 320548582..81b20e8f8 100644 --- a/feincms/utils/html/tidy.py +++ b/feincms/utils/html/tidy.py @@ -3,7 +3,16 @@ import re import tidylib -from feincms.utils.compat import text_type, unichr +from django.utils import six + + +try: + # Python 2 + unichr +except NameError: + # Python 3 + unichr = chr + # Based on http://stackoverflow.com/questions/92438/stripping-non-printable-characters-from-a-string-in-python # @@ -26,7 +35,7 @@ def tidy_html(html): Input must be unicode. Output will be valid XHTML. """ - if not isinstance(html, text_type): + if not isinstance(html, six.text_type): raise ValueError("tidyhtml must be called with a Unicode string!") errors = list() From bd8836165133b5c11d4d2dd4f4085e79d5dae7bc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 25 Oct 2013 15:52:16 +0200 Subject: [PATCH 0794/1590] Remove another explicit #page_form reference --- feincms/static/feincms/item_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 878c0a247..7ee59b0f9 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -468,7 +468,7 @@ if(!Array.indexOf) { /* Simulate a click on the save button instead of form.submit(), so that the submit handlers from FilteredSelectMultiple get invoked. See Issue #372 */ - $('#page_form input[type=submit][name=_save]').click(); + form_element.find('input[type=submit][name=_save]').click(); } else { $("div#popup_bg").remove(); From a795462ffb2a3af7b101f0c6b966c24c5ec9e68e Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 31 Oct 2013 18:25:36 +0100 Subject: [PATCH 0795/1590] tinymce4 template: do not init editors more than once, instead do that in the init cb. Also wrap triggerSave() in try/catch, this failed a couple of times for me when adding/removing rich text contents. --- .../admin/content/richtext/init_tinymce4.html | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/feincms/templates/admin/content/richtext/init_tinymce4.html b/feincms/templates/admin/content/richtext/init_tinymce4.html index ca18de6c7..6a3f7b6f5 100644 --- a/feincms/templates/admin/content/richtext/init_tinymce4.html +++ b/feincms/templates/admin/content/richtext/init_tinymce4.html @@ -13,39 +13,37 @@ (function($){ var tinymce_added = {}; + var tinymce_options = { +{% block settings %} + height: '300', + {% if TINYMCE_CONTENT_CSS_URL %}content_css: "{{ TINYMCE_CONTENT_CSS_URL }}",{% endif %} + {% if TINYMCE_LINK_LIST_URL %}link_list: "{{ TINYMCE_LINK_LIST_URL }}",{% endif %} + plugins: "{% block plugins %}fullscreen paste link{% endblock %}", + paste_auto_cleanup_on_paste: true, + relative_urls: false, + invalid_elements: 'script', + statusbar: false +{% endblock %} + }; function feincms_richtext_remove_tinymce(field) { var id = field ? field.id : this.id; if(tinymce_added[id]) { - tinyMCE.triggerSave(); - tinyMCE.remove({selector: '#' + id}); + tinyMCE.execCommand('mceRemoveEditor', false, id) tinymce_added[id] = false; } } function feincms_richtext_add_tinymce(field) { - var tinymce_options = { -{% block settings %} - height: '300', - {% if TINYMCE_CONTENT_CSS_URL %}content_css: "{{ TINYMCE_CONTENT_CSS_URL }}",{% endif %} - {% if TINYMCE_LINK_LIST_URL %}link_list: "{{ TINYMCE_LINK_LIST_URL }}",{% endif %} - plugins: "{% block plugins %}fullscreen paste link{% endblock %}", - paste_auto_cleanup_on_paste: true, - relative_urls: false, - invalid_elements: 'script', - statusbar: false -{% endblock %} - }; - var id = field ? field.id : this.id; if(!tinymce_added[id]) { - tinymce_options.selector = '#' + id; - tinyMCE.init(tinymce_options); + tinyMCE.execCommand('mceAddEditor', false, id) tinymce_added[id] = true; } } var richtext_init_fn = function(){ + tinyMCE.init(tinymce_options); $('{% block selectors %}.order-machine textarea.item-richtext, #frontend_editor textarea.item-richtext{% endblock %}').each(function(){ feincms_richtext_add_tinymce(this); }); @@ -54,6 +52,11 @@ {% block enable %} contentblock_init_handlers.push(richtext_init_fn); contentblock_move_handlers.poorify.push(function(item) { + try { + tinyMCE.triggerSave(); + } catch (error) { + alert("tinymce failed: " + error); + } item.find('textarea.item-richtext').each(feincms_richtext_remove_tinymce); }); contentblock_move_handlers.richify.push(function(item) { From 0379ae0410c7653d5832c0e4e72e6a21eace21fc Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 5 Nov 2013 18:15:03 +0100 Subject: [PATCH 0796/1590] tree_editor: Make sure we always show the filter sidebar, even if there are no filters, so that the expand/collapse tree shortcuts are always visible. --- feincms/admin/tree_editor.py | 5 ++++- .../templates/admin/feincms/tree_editor.html | 18 +++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 765b469f8..42b9b1614 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -155,8 +155,11 @@ def __init__(self, request, *args, **kwargs): def get_query_set(self, *args, **kwargs): mptt_opts = self.model._mptt_meta - return super(ChangeList, self).get_query_set(*args, **kwargs).\ + qs = super(ChangeList, self).get_query_set(*args, **kwargs).\ order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr) + # Force has_filters, so that the expand/collapse in sidebar is visible + self.has_filters = True + return qs def get_results(self, request): mptt_opts = self.model._mptt_meta diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index faa1ae6fc..10ca97294 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -20,16 +20,16 @@ {% block filters %} - {% if cl.has_filters %} -

-

{% trans 'Shortcuts' %}

- +
+

{% trans 'Shortcuts' %}

+ + {% if cl.filter_specs %}

{% trans 'Filter' %}

{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %} -
- {% endif %} + {% endif %} +
{% endblock %} From 3d9d3a7e2bf79ac045cd4f1d967b1e7a93f84bed Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 14:28:49 +0200 Subject: [PATCH 0797/1590] Ensure the PK field is rendered in inline admin forms --- feincms/templates/admin/feincms/content_inline.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templates/admin/feincms/content_inline.html b/feincms/templates/admin/feincms/content_inline.html index b16914984..69f7af25a 100644 --- a/feincms/templates/admin/feincms/content_inline.html +++ b/feincms/templates/admin/feincms/content_inline.html @@ -40,7 +40,7 @@

{{ inline_admin_formset.opts.verbose_name|title }}:  {% endfor %} - {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %} + {% if inline_admin_form.has_auto_field or inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} {{ inline_admin_form.fk_field.field }}

{% endfor %} From 54e7b2ddfee91d3e31e332644080a0d95d1fca12 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Oct 2013 14:32:59 +0200 Subject: [PATCH 0798/1590] Remove @commit_on_success, this should really not be necessary anymore --- feincms/module/page/models.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 92a640122..5df5e93fc 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -11,7 +11,6 @@ from django.db.models.loading import get_model from django.http import Http404 from django.utils.translation import ugettext_lazy as _ -from django.db.transaction import commit_on_success from mptt.models import MPTTModel @@ -231,7 +230,6 @@ def __init__(self, *args, **kwargs): # determine whether it has been changed in the save handler: self._original_cached_url = self._cached_url - @commit_on_success def save(self, *args, **kwargs): """ Overridden save method which updates the ``_cached_url`` attribute of @@ -277,7 +275,6 @@ def save(self, *args, **kwargs): super(BasePage, page).save() # do not recurse save.alters_data = True - @commit_on_success def delete(self, *args, **kwargs): super(BasePage, self).delete(*args, **kwargs) self.invalidate_cache() From 0f51580009892db7aff81196f068a9652324f2e0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 7 Nov 2013 10:24:29 +0100 Subject: [PATCH 0799/1590] FeinCMS v1.7.7 The hopefully-compatible-with-Django-1.6-release. --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 53891bf46..60edfc9ca 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 7, 6) +VERSION = (1, 7, 7) __version__ = '.'.join(map(str, VERSION)) From 5110a8008728061ad3e57ea403e9d09caaaddd81 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 7 Nov 2013 10:34:17 +0100 Subject: [PATCH 0800/1590] Django 1.6 has been released, run tests with the release version now --- .travis.yml | 5 +++-- tests/tox-update-venvs.sh | 8 -------- tests/tox.ini | 6 +++--- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 510d5d706..eff3b6408 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,9 @@ python: - "2.7" - "2.6" env: - - DJANGO_VERSION=1.4.2 - - DJANGO_VERSION=1.5.0 + - DJANGO_VERSION=1.4.10 + - DJANGO_VERSION=1.5.5 + - DJANGO_VERSION=1.6.0 # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q Django==$DJANGO_VERSION django-mptt Pillow feedparser --use-mirrors diff --git a/tests/tox-update-venvs.sh b/tests/tox-update-venvs.sh index 2fabbab8b..103984fb9 100755 --- a/tests/tox-update-venvs.sh +++ b/tests/tox-update-venvs.sh @@ -1,17 +1,9 @@ #!/bin/sh -( - cd .tox/py27-1.6.X - bin/pip install -U --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev -) ( cd .tox/py27-1.7.X bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev ) -( - cd .tox/py33-1.6.X - bin/pip install -U --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev -) ( cd .tox/py33-1.7.X bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev diff --git a/tests/tox.ini b/tests/tox.ini index b1abf4b62..6a14ca64f 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -64,7 +64,7 @@ deps = [testenv:py26-1.6.X] basepython = python2.6 deps = - --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev + Django==1.6.0 django-mptt==0.6.0 Pillow==2.1.0 feedparser==5.1.3 @@ -74,7 +74,7 @@ deps = [testenv:py27-1.6.X] basepython = python2.7 deps = - --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev + Django==1.6.0 django-mptt==0.6.0 Pillow==2.1.0 feedparser==5.1.3 @@ -104,7 +104,7 @@ deps = [testenv:py33-1.6.X] basepython = python3.3 deps = - --editable=git+git://github.com/django/django.git@stable/1.6.x#egg=django-dev + Django==1.6.0 django-mptt==0.6.0 Pillow==2.1.0 feedparser==5.1.3 From 913433cef7c7cc64d91dd72fe0ed69af45138ee8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 7 Nov 2013 10:49:03 +0100 Subject: [PATCH 0801/1590] Let's see what happens if we add Python3.3 to the travis-ci matrix --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index eff3b6408..19723fc4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,15 @@ language: python python: - "2.7" - "2.6" + - "3.3" env: - DJANGO_VERSION=1.4.10 - DJANGO_VERSION=1.5.5 - DJANGO_VERSION=1.6.0 +matrix: + exclude: + - python: "3.3" + env: DJANGO_VERSION=1.4.10 # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q Django==$DJANGO_VERSION django-mptt Pillow feedparser --use-mirrors From 35d6a262a9ae0747cf8b46817a56292407f6bace Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 8 Nov 2013 10:20:13 +0100 Subject: [PATCH 0802/1590] Stop registering and reregistering extensions in the testsuite --- tests/testapp/models.py | 10 ++++++++++ tests/testapp/tests/test_extensions.py | 12 +----------- tests/testapp/tests/test_page.py | 18 ------------------ tests/testapp/tests/utils.py | 23 ++--------------------- 4 files changed, 13 insertions(+), 50 deletions(-) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index fe11e51f3..96bb1ff99 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -81,6 +81,16 @@ def children(self, page, **kwargs): Page.register_extensions( 'feincms.module.page.extensions.navigation', 'feincms.module.page.extensions.sites', + 'feincms.module.extensions.translations', + 'feincms.module.extensions.datepublisher', + 'feincms.module.extensions.translations', + 'feincms.module.extensions.ct_tracker', + 'feincms.module.extensions.seo', + 'feincms.module.extensions.changedate', + 'feincms.module.extensions.seo', # duplicate + 'feincms.module.page.extensions.navigation', + 'feincms.module.page.extensions.symlinks', + 'feincms.module.page.extensions.titles', ) diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 8dccb7014..ddb2a8157 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -9,17 +9,7 @@ from feincms.module.page.models import Page -from .utils import reset_page_db - - - class TranslationTestCase(TestCase): - - @classmethod - def setUpClass(cls): - Page.register_extensions('feincms.module.extensions.translations',) - reset_page_db() - def setUp(self): Page.register_templates({ 'key': 'base', @@ -71,4 +61,4 @@ def testPage(self): self.assertEqual(self.page_de.original_translation, self.page_en) # TODO: add request tests - # with translation.override('de'): \ No newline at end of file + # with translation.override('de'): diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 7190897fd..4381142bc 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -39,28 +39,10 @@ from feincms.translations import short_language_code from .test_stuff import Empty -from .utils import reset_page_db # ------------------------------------------------------------------------ class PagesTestCase(TestCase): - - @classmethod - def setUpClass(cls): - Page.register_extensions( - 'feincms.module.extensions.datepublisher', - 'feincms.module.extensions.translations', - 'feincms.module.extensions.ct_tracker', - 'feincms.module.extensions.seo', - 'feincms.module.extensions.changedate', - 'feincms.module.extensions.seo', # duplicate - 'feincms.module.page.extensions.navigation', - 'feincms.module.page.extensions.symlinks', - 'feincms.module.page.extensions.titles', - ) - reset_page_db() - - def setUp(self): u = User(username='test', is_active=True, is_staff=True, is_superuser=True) u.set_password('test') diff --git a/tests/testapp/tests/utils.py b/tests/testapp/tests/utils.py index cfe6204b7..31ca0639e 100644 --- a/tests/testapp/tests/utils.py +++ b/tests/testapp/tests/utils.py @@ -1,12 +1,8 @@ # coding: utf-8 -from django.core.management import CommandError -from django.core.management.color import no_style -from django.core.management.sql import sql_delete, sql_all -from django.db import connections, transaction, DEFAULT_DB_ALIAS -import feincms.models import datetime + def mock_datetime(): class MockDatetime(datetime.datetime): @classmethod @@ -14,25 +10,10 @@ def now(cls): return datetime.datetime(2012, 6, 1) return MockDatetime + def mock_date(): class MockDate(datetime.date): @classmethod def today(cls): return datetime.date(2012, 6, 1) return MockDate - - -def reset_page_db(): - using = DEFAULT_DB_ALIAS - connection = connections[using] - sql_list = sql_delete(feincms.module.page.models, no_style(), connection) - sql_list += sql_all(feincms.module.page.models, no_style(), connection) - try: - cursor = connection.cursor() - for sql in sql_list: - cursor.execute(sql) - except Exception as e: - transaction.rollback_unless_managed() - raise CommandError("Error: database couldn't be reset: %s" % e) - else: - transaction.commit_unless_managed() From c9437c3f385698b80414aadf48f81d6902e6d08a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 8 Nov 2013 10:26:25 +0100 Subject: [PATCH 0803/1590] Add travis CI images to the readme --- README.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.rst b/README.rst index aa86d8e25..283074a8d 100644 --- a/README.rst +++ b/README.rst @@ -115,3 +115,10 @@ rewinding policies are described below. * ``pu`` or feature branches are used for short-lived projects. These branches aren't guaranteed to stay around and are not meant to be deployed into production environments. + + +Travis CI +========= + +.. image:: https://travis-ci.org/feincms/feincms.png?branch=next :target: https://travis-ci.org/feincms/feincms +.. image:: https://travis-ci.org/feincms/feincms.png?branch=master :target: https://travis-ci.org/feincms/feincms From 69694c67e6fdd1501d5da37ea0e0bde91dba494a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 8 Nov 2013 10:27:41 +0100 Subject: [PATCH 0804/1590] Try again --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 283074a8d..5a3b9c7e7 100644 --- a/README.rst +++ b/README.rst @@ -120,5 +120,5 @@ rewinding policies are described below. Travis CI ========= -.. image:: https://travis-ci.org/feincms/feincms.png?branch=next :target: https://travis-ci.org/feincms/feincms -.. image:: https://travis-ci.org/feincms/feincms.png?branch=master :target: https://travis-ci.org/feincms/feincms +.. image:: https://travis-ci.org/feincms/feincms.png?branch=next +.. image:: https://travis-ci.org/feincms/feincms.png?branch=master From a73a93f2b6b47f0d3677a2fb2e48368bdb1113e7 Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Fri, 8 Nov 2013 21:41:44 +1100 Subject: [PATCH 0805/1590] Fixed broken content type headings when class name contains an underscore. (No, I don't use underscores in class names, except when doing crazy namespacing stuff for multiple FeinCMS base classes sharing the same content types...) --- feincms/static/feincms/item_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 753b8f0be..aa2d70d8e 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -503,7 +503,7 @@ if(!Array.indexOf) { elem.find(".region-choice-field").val()); if (REGION_MAP[region_id] != undefined) { var content_type = elem.attr("id").substr( - 0, elem.attr("id").indexOf("_")); + 0, elem.attr("id").lastIndexOf("_")); var item = create_new_item_from_form( elem, CONTENT_NAMES[content_type], content_type); add_fieldset(region_id, item, {where:'append'}); From be9aa2f7afc797cc5cad43328034f57823e55ae0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 8 Nov 2013 12:14:08 +0100 Subject: [PATCH 0806/1590] ensure_completely_loaded: Only set COMPLETELY_LOADED to True if app cache is ready Refs #323. Thanks to Simon Meers for the report and for finding a solution. --- feincms/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 60edfc9ca..f85a48d90 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -72,5 +72,6 @@ def ensure_completely_loaded(force=False): # See Issue #323 on github. loading.cache._get_models_cache.clear() - COMPLETELY_LOADED = True + if loading.app_cache_ready(): + COMPLETELY_LOADED = True return True From 0498f6328539006d13035d614e0c9f3a1af235ae Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 8 Nov 2013 12:25:32 +0100 Subject: [PATCH 0807/1590] Add an implementation of Array.lastIndexOf to ie_compat.js --- feincms/static/feincms/ie_compat.js | 40 ++++++++++++++++++- .../templates/admin/feincms/item_editor.html | 1 + 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/feincms/static/feincms/ie_compat.js b/feincms/static/feincms/ie_compat.js index 25a245a64..f10fa4b93 100644 --- a/feincms/static/feincms/ie_compat.js +++ b/feincms/static/feincms/ie_compat.js @@ -57,4 +57,42 @@ if (!Array.prototype.map) return res; }; -} \ No newline at end of file +} + +// Thanks https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf +if (!Array.prototype.lastIndexOf) { + Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) { + 'use strict'; + + if (this == null) { + throw new TypeError(); + } + + var n, k, + t = Object(this), + len = t.length >>> 0; + if (len === 0) { + return -1; + } + + n = len; + if (arguments.length > 1) { + n = Number(arguments[1]); + if (n != n) { + n = 0; + } + else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + + for (k = n >= 0 + ? Math.min(n, len - 1) + : len - Math.abs(n); k >= 0; k--) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; +} diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index bcccf0387..4ae740b76 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -18,6 +18,7 @@ {% endif %} }; + {% include "admin/feincms/_messages_js.html" %} From 788da0d91c3f4c2d23a10a7cd53963207473ecb2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 8 Nov 2013 16:01:48 +0100 Subject: [PATCH 0808/1590] Work on app_reverse and the 1.8 release notes a bit --- docs/integration.rst | 11 +++++++++++ docs/releases/1.8.rst | 23 +++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/docs/integration.rst b/docs/integration.rst index 793e8fb68..6883bfd2e 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -314,6 +314,17 @@ Storing the URL in a context variable is supported too:: {% load applicationcontent_tags %} {% app_reverse "mymodel_detail" "myapp.urls" arg1 arg2 as url %} +Inside the app (in this case, inside the views defined in ``myapp.urls``), +you can also pass the current request instance instead of the URLconf +name. + +If an application has been added several times to the same page tree, +``app_reverse`` tries to find the best match. The logic is contained inside +``ApplicationContent.closest_match``, and can be overridden by subclassing +the application content type. The default implementation only takes the current +language into account, which is mostly helpful when you're using the +translations page extension. + Additional customization possibilities -------------------------------------- diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index 6fde94c7f..db6ee5f10 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -5,6 +5,14 @@ FeinCMS 1.8 release notes (upcoming) Welcome to FeinCMS 1.8! +FeinCMS finally got continuous integration +========================================== + +Have a look at the status page here: + +`Travis CI `_ + + Preliminary Python 3.3 support ============================== @@ -34,6 +42,11 @@ Backwards-incompatible changes is considered more important for template resolution than the section content type. +* The mechanism for finding the best application content match has been + massively simplified and also made customizable. The default implementation + of ``ApplicationContent.closest_match`` now only takes the current language + into account. + Removal of deprecated features ------------------------------ @@ -71,13 +84,6 @@ Removal of deprecated features anything for some time now. -New deprecations ----------------- - -* ``Page.setup_request()`` does not do anything anymore and will be removed - in FeinCMS v1.8. - - Notable features and improvements ================================= @@ -105,4 +111,5 @@ Bugfixes Compatibility with Django and other apps ======================================== -FeinCMS 1.8 requires Django 1.4 (or even Django 1.5?). +FeinCMS 1.8 requires Django 1.4 or better. The testsuite is successfully run +against Django 1.4, 1.5, 1.6 and the upcoming 1.7. From 2a0cc95a2b653615ed5d69802f2cb13985b05eaa Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 15:29:46 +0200 Subject: [PATCH 0809/1590] app_reverse: Massive simplification, only take the urlconf and the language into account by default --- feincms/content/application/models.py | 176 ++++++++------------------ tests/testapp/tests/test_page.py | 16 ++- 2 files changed, 64 insertions(+), 128 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 8a0d082e2..bfe476a59 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -4,48 +4,22 @@ from email.utils import parsedate from time import mktime +from random import SystemRandom import re +from django.core.cache import cache from django.core.urlresolvers import Resolver404, resolve, reverse, NoReverseMatch from django.db import models from django.db.models import signals from django.http import HttpResponse from django.utils.functional import curry as partial, lazy, wraps from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import get_language, ugettext_lazy as _ from feincms.admin.item_editor import ItemEditorForm from feincms.contrib.fields import JSONField from feincms.utils import get_object -try: - from threading import local -except ImportError: - from django.utils._threading_local import local - -# Used to store MPTT informations about the currently requested -# page. The information will be used to find the best application -# content instance if a particular application has been added -# more than once to the current website. -# Additionally, we store the page class too, because when we have -# more than one page class, reverse() will want to prefer the page -# class used to render the current page. (See issue #240) -_local = local() - - -def retrieve_page_information(page, request=None): - """This is the request processor responsible for retrieving information - about the currently processed page so that we can make an optimal match - when reversing app URLs when the same ApplicationContent has been added - several times to the website.""" - _local.proximity_info = (page.tree_id, page.lft, page.rght, page.level) - _local.page_class = page.__class__ - _local.page_cache_key_fn = page.cache_key - - -def _empty_reverse_cache(*args, **kwargs): - _local.reverse_cache = {} - def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, **vkwargs): @@ -76,97 +50,20 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, # vargs and vkwargs are used to send through additional parameters which # are uninteresting to us (such as current_app) - # get additional cache keys from the page if available - # refs https://github.com/feincms/feincms/pull/277/ - fn = getattr(_local, 'page_cache_key_fn', lambda: '') - cache_key_prefix = fn() - - app_cache_keys = { - 'none': '%s:app_%s_none' % (cache_key_prefix, urlconf), - } - proximity_info = getattr(_local, 'proximity_info', None) + applicationcontent_class = ApplicationContent._feincms_content_models[0] + content = applicationcontent_class.closest_match(urlconf) url_prefix = None - if proximity_info: - app_cache_keys.update({ - 'all': '%s:app_%s_%s_%s_%s_%s' % ( - (cache_key_prefix, urlconf,) + proximity_info), - 'tree': '%s:app_%s_%s' % ( - cache_key_prefix, urlconf, proximity_info[0]), - }) - - for key in ('all', 'tree', 'none'): - try: - url_prefix = _local.reverse_cache[app_cache_keys[key]] - break - except (AttributeError, KeyError): - pass - else: - try: - # Take the ApplicationContent class used by the current request - model_class = _local.page_class.content_type_for(ApplicationContent) - except AttributeError: - model_class = None - - if not model_class: - # Take any - model_class = ApplicationContent._feincms_content_models[0] - - # TODO: Only active pages? What about multisite support? - contents = model_class.objects.filter( - urlconf_path=urlconf).select_related('parent') - - if proximity_info: - # find the closest match within the same subtree - tree_contents = contents.filter(parent__tree_id=proximity_info[0]) - if not len(tree_contents): - # no application contents within the same tree - cache_key = 'tree' - try: - content = contents[0] - except IndexError: - content = None - elif len(tree_contents) == 1: - cache_key = 'tree' - # just one match within the tree, use it - content = tree_contents[0] - else: # len(tree_contents) > 1 - cache_key = 'all' - try: - # select all ancestors and descendants and get the one with - # the smallest difference in levels - content = (tree_contents.filter( - parent__rght__gt=proximity_info[2], - parent__lft__lt=proximity_info[1] - ) | tree_contents.filter( - parent__lft__lte=proximity_info[2], - parent__lft__gte=proximity_info[1], - )).extra({ - 'level_diff': "abs(100 + level - %d)" % proximity_info[3] - }).order_by('level_diff')[0] - except IndexError: - content = tree_contents[0] - else: - cache_key = 'none' - try: - content = contents[0] - except IndexError: - content = None - - if content: - if urlconf in model_class.ALL_APPS_CONFIG: - # We have an overridden URLconf - urlconf = model_class.ALL_APPS_CONFIG[urlconf]['config'].get( - 'urls', urlconf) + if content: + if urlconf in applicationcontent_class.ALL_APPS_CONFIG: + # We have an overridden URLconf + urlconf = applicationcontent_class.ALL_APPS_CONFIG[urlconf]['config'].get( + 'urls', urlconf) - if not hasattr(_local, 'reverse_cache'): - _local.reverse_cache = {} + prefix = content.parent.get_absolute_url() + prefix += '/' if prefix[-1] != '/' else '' - prefix = content.parent.get_absolute_url() - prefix += '/' if prefix[-1] != '/' else '' - - _local.reverse_cache[app_cache_keys[cache_key]] = url_prefix = ( - urlconf, prefix) + url_prefix = (urlconf, prefix) if url_prefix: return reverse(viewname, @@ -175,6 +72,7 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, kwargs=kwargs, prefix=url_prefix[1], *vargs, **vkwargs) + raise NoReverseMatch("Unable to find ApplicationContent for %r" % urlconf) @@ -302,14 +200,13 @@ def save(self, commit=True, *args, **kwargs): # embedded instances: cls.feincms_item_editor_form = ApplicationContentItemEditorForm - # Make sure the patched reverse() method has all information it needs + # Clobber the app_reverse cache when saving application contents + # and/or pages page_class = cls.parent.field.rel.to - page_class.register_request_processor(retrieve_page_information) - - signals.post_save.connect(_empty_reverse_cache, sender=cls) - signals.post_delete.connect(_empty_reverse_cache, sender=cls) - signals.post_save.connect(_empty_reverse_cache, sender=page_class) - signals.post_delete.connect(_empty_reverse_cache, sender=page_class) + signals.post_save.connect(new_app_reverse_cache_generation, sender=cls) + signals.post_delete.connect(new_app_reverse_cache_generation, sender=cls) + signals.post_save.connect(new_app_reverse_cache_generation, sender=page_class) + signals.post_delete.connect(new_app_reverse_cache_generation, sender=page_class) def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) @@ -436,3 +333,36 @@ def _update_response_headers(self, request, response, headers): lm_list = [parsedate(x) for x in headers.get('Expires', ())] if len(lm_list) > 0: response['Expires'] = http_date(mktime(min(lm_list))) + + @classmethod + def closest_match(cls, urlconf_path): + cache_generation = cache.get('app_reverse_cache_generation') + if cache_generation is None: + new_app_reverse_cache_generation() + cache_generation = cache.get('app_reverse_cache_generation') + + cache_key = '%s-%s-%s' % (urlconf_path, get_language(), cache_generation) + value = cache.get(cache_key) + + if value is None: + applicationcontent_class = cls._feincms_content_models[0] + page_class = applicationcontent_class.parent.field.rel.to + + try: + value = applicationcontent_class.objects.filter( + parent__in=page_class.objects.active(), + urlconf_path=urlconf_path, + ).order_by('pk').select_related('parent')[0] + except IndexError: + value = None + + cache.set(cache_key, value) + + return value + + +def new_app_reverse_cache_generation(*args, **kwargs): + """Does not really empty the cache; instead it adds a random element to the + cache key generation which guarantees that the cache does not yet contain + values for all newly generated keys""" + cache.set('app_reverse_cache_generation', str(SystemRandom().random())) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 4381142bc..29c05e195 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -25,7 +25,8 @@ from django.utils.encoding import force_text from feincms import settings as feincms_settings -from feincms.content.application.models import _empty_reverse_cache, app_reverse +from feincms.content.application.models import (app_reverse, + new_app_reverse_cache_generation) from feincms.content.image.models import ImageContent from feincms.content.raw.models import RawContent from feincms.content.richtext.models import RichTextContent @@ -1125,7 +1126,7 @@ def test_25_applicationcontent(self): self.assertNumQueries(0, lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) - _empty_reverse_cache() + new_app_reverse_cache_generation() self.assertNumQueries(1, lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) @@ -1226,8 +1227,8 @@ def test_28_applicationcontent_reverse(self): self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), page.get_absolute_url()) - # when specific applicationcontent exists more then once reverse should return url - # for the one that has tree_id same as current feincms page + # when specific applicationcontent exists more then once reverse should + # return the URL of the first (ordered by primary key) page. self.login() self.create_page_through_admin(title='Home DE', language='de', active=True) page_de = Page.objects.get(title='Home DE') @@ -1236,13 +1237,18 @@ def test_28_applicationcontent_reverse(self): page_de_1.applicationcontent_set.create( region='main', ordering=0, urlconf_path='testapp.applicationcontent_urls') - _empty_reverse_cache() + + page.active = False + page.save() settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), 'templates'),) self.client.get(page_de_1.get_absolute_url()) self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), page_de_1.get_absolute_url()) + page.active = True + page.save() + self.client.get(page1.get_absolute_url()) self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), page.get_absolute_url()) From f23e6fecb233541ca748fc15ce705e8d5caf61b6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 21 Oct 2013 15:38:27 +0200 Subject: [PATCH 0810/1590] Actually do what the pull request says --- feincms/content/application/models.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index bfe476a59..d7adbd90c 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -18,6 +18,7 @@ from feincms.admin.item_editor import ItemEditorForm from feincms.contrib.fields import JSONField +from feincms.translations import short_language_code from feincms.utils import get_object @@ -348,11 +349,27 @@ def closest_match(cls, urlconf_path): applicationcontent_class = cls._feincms_content_models[0] page_class = applicationcontent_class.parent.field.rel.to + filters = { + 'parent__in': page_class.objects.active(), + 'urlconf_path': urlconf_path, + } + + contents = applicationcontent_class.objects.filter( + **filters).order_by('pk').select_related('parent') + + if len(contents) > 1: + try: + current = short_language_code(get_language()) + contents = [ + content for content in contents if + short_language_code(content.parent.language) == current] + value = contents[0] + + except (AttributeError, IndexError): + pass + try: - value = applicationcontent_class.objects.filter( - parent__in=page_class.objects.active(), - urlconf_path=urlconf_path, - ).order_by('pk').select_related('parent')[0] + value = contents[0] except IndexError: value = None From 24732d36ee01468ec9d8c12e190715499f22ff2e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 22 Oct 2013 08:23:59 +0200 Subject: [PATCH 0811/1590] app_reverse: Actually fall back to any language if current language does not exist Thanks for noticing, Marc Egli. --- feincms/content/application/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index d7adbd90c..1496f5883 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -360,10 +360,10 @@ def closest_match(cls, urlconf_path): if len(contents) > 1: try: current = short_language_code(get_language()) - contents = [ + value = [ content for content in contents if - short_language_code(content.parent.language) == current] - value = contents[0] + short_language_code(content.parent.language) == current + ][0] except (AttributeError, IndexError): pass From ad4d9fde1dd6fb44cfb4f64e9e84fe2747e04ea9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 22 Oct 2013 09:31:52 +0200 Subject: [PATCH 0812/1590] Remove an unnecessary assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks Simon Bächler for noticing. --- feincms/content/application/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 1496f5883..d6a4d869a 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -371,7 +371,7 @@ def closest_match(cls, urlconf_path): try: value = contents[0] except IndexError: - value = None + pass cache.set(cache_key, value) From cc674c35ba0b2cb442e399113253e96627287d4d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 22 Oct 2013 10:54:03 +0200 Subject: [PATCH 0813/1590] Simplify ApplicationContent.closest_match by moving the caching into app_reverse Also, only cache (urlconf, prefix) instead of the model. --- feincms/content/application/models.py | 99 +++++++++++++-------------- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index d6a4d869a..9938e8cee 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -22,6 +22,13 @@ from feincms.utils import get_object +def new_app_reverse_cache_generation(*args, **kwargs): + """Does not really empty the cache; instead it adds a random element to the + cache key generation which guarantees that the cache does not yet contain + values for all newly generated keys""" + cache.set('app_reverse_cache_generation', str(SystemRandom().random())) + + def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, **vkwargs): """ @@ -48,25 +55,33 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, appconfig = extra_context.get('app_config', {}) urlconf = appconfig.get('urlconf_path', urlconf) - # vargs and vkwargs are used to send through additional parameters which - # are uninteresting to us (such as current_app) + cache_generation = cache.get('app_reverse_cache_generation') + if cache_generation is None: + new_app_reverse_cache_generation() + cache_generation = cache.get('app_reverse_cache_generation') + + cache_key = '%s-%s-%s' % (urlconf, get_language(), cache_generation) + url_prefix = cache.get(cache_key) - applicationcontent_class = ApplicationContent._feincms_content_models[0] - content = applicationcontent_class.closest_match(urlconf) - url_prefix = None + if url_prefix is None: + appcontent_class = ApplicationContent._feincms_content_models[0] + content = appcontent_class.closest_match(urlconf) - if content: - if urlconf in applicationcontent_class.ALL_APPS_CONFIG: - # We have an overridden URLconf - urlconf = applicationcontent_class.ALL_APPS_CONFIG[urlconf]['config'].get( - 'urls', urlconf) + if content is not None: + if urlconf in appcontent_class.ALL_APPS_CONFIG: + # We have an overridden URLconf + app_config = appcontent_class.ALL_APPS_CONFIG[urlconf] + urlconf = app_config['config'].get('urls', urlconf) - prefix = content.parent.get_absolute_url() - prefix += '/' if prefix[-1] != '/' else '' + prefix = content.parent.get_absolute_url() + prefix += '/' if prefix[-1] != '/' else '' - url_prefix = (urlconf, prefix) + url_prefix = (urlconf, prefix) + cache.set(cache_key, url_prefix) if url_prefix: + # vargs and vkwargs are used to send through additional parameters + # which are uninteresting to us (such as current_app) return reverse(viewname, url_prefix[0], args=args, @@ -337,49 +352,27 @@ def _update_response_headers(self, request, response, headers): @classmethod def closest_match(cls, urlconf_path): - cache_generation = cache.get('app_reverse_cache_generation') - if cache_generation is None: - new_app_reverse_cache_generation() - cache_generation = cache.get('app_reverse_cache_generation') - - cache_key = '%s-%s-%s' % (urlconf_path, get_language(), cache_generation) - value = cache.get(cache_key) - - if value is None: - applicationcontent_class = cls._feincms_content_models[0] - page_class = applicationcontent_class.parent.field.rel.to - - filters = { - 'parent__in': page_class.objects.active(), - 'urlconf_path': urlconf_path, - } - - contents = applicationcontent_class.objects.filter( - **filters).order_by('pk').select_related('parent') - - if len(contents) > 1: - try: - current = short_language_code(get_language()) - value = [ - content for content in contents if - short_language_code(content.parent.language) == current - ][0] + page_class = cls.parent.field.rel.to - except (AttributeError, IndexError): - pass + contents = cls.objects.filter( + parent__in=page_class.objects.active(), + urlconf_path=urlconf_path, + ).order_by('pk').select_related('parent') + if len(contents) > 1: try: - value = contents[0] - except IndexError: - pass - - cache.set(cache_key, value) + current = short_language_code(get_language()) + return [ + content for content in contents if + short_language_code(content.parent.language) == current + ][0] - return value + except (AttributeError, IndexError): + pass + try: + return contents[0] + except IndexError: + pass -def new_app_reverse_cache_generation(*args, **kwargs): - """Does not really empty the cache; instead it adds a random element to the - cache key generation which guarantees that the cache does not yet contain - values for all newly generated keys""" - cache.set('app_reverse_cache_generation', str(SystemRandom().random())) + return None From 91b3bc4853d79e64b04df2208352dd656e50747b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 28 Oct 2013 08:21:43 +0100 Subject: [PATCH 0814/1590] app_reverse cache: Also use settings.SITE_ID if set --- feincms/content/application/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 9938e8cee..921f3ca58 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -7,6 +7,7 @@ from random import SystemRandom import re +from django.conf import settings from django.core.cache import cache from django.core.urlresolvers import Resolver404, resolve, reverse, NoReverseMatch from django.db import models @@ -60,7 +61,12 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, new_app_reverse_cache_generation() cache_generation = cache.get('app_reverse_cache_generation') - cache_key = '%s-%s-%s' % (urlconf, get_language(), cache_generation) + cache_key = '%s-%s-%s-%s' % ( + urlconf, + get_language(), + getattr(settings, 'SITE_ID', 0), + cache_generation) + url_prefix = cache.get(cache_key) if url_prefix is None: From a1f0d142f3021beb30962a0e28058dbcf3644d8d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 28 Oct 2013 08:24:29 +0100 Subject: [PATCH 0815/1590] Protect the app_reverse cache against offline database changes --- feincms/content/application/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 921f3ca58..ac00c8c71 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -30,6 +30,11 @@ def new_app_reverse_cache_generation(*args, **kwargs): cache.set('app_reverse_cache_generation', str(SystemRandom().random())) +# Set the app_reverse_cache_generation value once per startup (at least). +# This protects us against offline modifications of the database. +new_app_reverse_cache_generation() + + def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, *vargs, **vkwargs): """ @@ -58,6 +63,7 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, cache_generation = cache.get('app_reverse_cache_generation') if cache_generation is None: + # This might never happen. Still, better be safe than sorry. new_app_reverse_cache_generation() cache_generation = cache.get('app_reverse_cache_generation') From 07db8480c2c399d0920fe45a43de50e509b47a71 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 28 Oct 2013 08:27:24 +0100 Subject: [PATCH 0816/1590] =?UTF-8?q?Follow=20the=20advice=20of=20Simon=20?= =?UTF-8?q?B=C3=A4chler=20and=20do=20not=20use=20new=5F*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feincms/content/application/models.py | 14 +++++++------- tests/testapp/tests/test_page.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index ac00c8c71..f0d35dbb4 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -23,7 +23,7 @@ from feincms.utils import get_object -def new_app_reverse_cache_generation(*args, **kwargs): +def cycle_app_reverse_cache(*args, **kwargs): """Does not really empty the cache; instead it adds a random element to the cache key generation which guarantees that the cache does not yet contain values for all newly generated keys""" @@ -32,7 +32,7 @@ def new_app_reverse_cache_generation(*args, **kwargs): # Set the app_reverse_cache_generation value once per startup (at least). # This protects us against offline modifications of the database. -new_app_reverse_cache_generation() +cycle_app_reverse_cache() def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, @@ -64,7 +64,7 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, cache_generation = cache.get('app_reverse_cache_generation') if cache_generation is None: # This might never happen. Still, better be safe than sorry. - new_app_reverse_cache_generation() + cycle_app_reverse_cache() cache_generation = cache.get('app_reverse_cache_generation') cache_key = '%s-%s-%s-%s' % ( @@ -231,10 +231,10 @@ def save(self, commit=True, *args, **kwargs): # Clobber the app_reverse cache when saving application contents # and/or pages page_class = cls.parent.field.rel.to - signals.post_save.connect(new_app_reverse_cache_generation, sender=cls) - signals.post_delete.connect(new_app_reverse_cache_generation, sender=cls) - signals.post_save.connect(new_app_reverse_cache_generation, sender=page_class) - signals.post_delete.connect(new_app_reverse_cache_generation, sender=page_class) + signals.post_save.connect(cycle_app_reverse_cache, sender=cls) + signals.post_delete.connect(cycle_app_reverse_cache, sender=cls) + signals.post_save.connect(cycle_app_reverse_cache, sender=page_class) + signals.post_delete.connect(cycle_app_reverse_cache, sender=page_class) def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 29c05e195..99a6485b0 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -26,7 +26,7 @@ from feincms import settings as feincms_settings from feincms.content.application.models import (app_reverse, - new_app_reverse_cache_generation) + cycle_app_reverse_cache) from feincms.content.image.models import ImageContent from feincms.content.raw.models import RawContent from feincms.content.richtext.models import RichTextContent @@ -1126,7 +1126,7 @@ def test_25_applicationcontent(self): self.assertNumQueries(0, lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) - new_app_reverse_cache_generation() + cycle_app_reverse_cache() self.assertNumQueries(1, lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) From e571cdcb7e778279c1dd4747935bed44bce3953d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 9 Nov 2013 13:48:29 +0100 Subject: [PATCH 0817/1590] Add a test confirming that invalid moves should not be accepted (model-level validation) Refs #480. --- tests/testapp/tests/test_page.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 99a6485b0..15d838ce3 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -8,7 +8,6 @@ import os import re - from django import forms, template from django.conf import settings from django.contrib.auth.models import User, AnonymousUser @@ -24,6 +23,8 @@ from django.utils import timezone from django.utils.encoding import force_text +from mptt.exceptions import InvalidMove + from feincms import settings as feincms_settings from feincms.content.application.models import (app_reverse, cycle_app_reverse_cache) @@ -1427,3 +1428,17 @@ def test_36_sitemaps(self): page.save() response = self.client.get('/sitemap.xml') self.assertContains(response, '', status_code=200) + + def test_37_invalid_parent(self): + self.create_default_page_set() + + page1, page2 = list(Page.objects.order_by('id')) + + page1.parent = page1 + self.assertRaises(InvalidMove, page1.save) + + self.create_page('Page 3', parent=page2) + page1, page2, page3 = list(Page.objects.order_by('id')) + + page1.parent = page3 + self.assertRaises(InvalidMove, page1.save) From d52f487a3911a928228087e717430e0d309e8811 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 9 Nov 2013 13:51:03 +0100 Subject: [PATCH 0818/1590] TreeEditor: Run the save() method of both instances involved in a node move --- feincms/admin/tree_editor.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 42b9b1614..e717bed92 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -469,13 +469,14 @@ def _move_node(self, request): self.message_user(request, u'%s' % e) return HttpResponse('FAIL') - # Ensure that model save method has been run (required to + # Ensure that model save methods have been run (required to # update Page._cached_url values, might also be helpful for other # models inheriting MPTTModel) - cut_item = queryset.get(pk=cut_item.pk) - cut_item.save() + for item in queryset.filter(id__in=(cut_item.pk, pasted_on.pk)): + item.save() - self.message_user(request, ugettext('%s has been moved to a new position.') % + self.message_user(request, + ugettext('%s has been moved to a new position.') % cut_item) return HttpResponse('OK') From 769d32175030763daecc7182f52ae068c248d97e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 9 Nov 2013 14:36:19 +0100 Subject: [PATCH 0819/1590] Remove an obsolete comment --- feincms/module/page/modeladmins.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index f02819ae8..80f01f70b 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -30,8 +30,6 @@ class Media: form = PageAdminForm - # the fieldsets config here is used for the add_view, it has no effect - # for the change_view which is completely customized anyway unknown_fields = ['template_key', 'parent', 'override_url', 'redirect_to'] fieldset_insertion_index = 2 fieldsets = [ From d9af2af18ec90317f2ba2d56f5635aca084f070f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 9 Nov 2013 14:46:24 +0100 Subject: [PATCH 0820/1590] Remove PageAdmin.unknown_fields Refs #482. --- docs/releases/1.8.rst | 4 ++++ feincms/module/page/modeladmins.py | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index db6ee5f10..d50595598 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -107,6 +107,10 @@ Bugfixes * The datepublisher response processor should not crash during daylight savings time changes anymore. +* The undocumented attribute ``PageAdmin.unknown_fields`` has been removed + because it was modified at class level and not instance level which made + reuse harder than necessary. + Compatibility with Django and other apps ======================================== diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 80f01f70b..47458d2e6 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -30,7 +30,6 @@ class Media: form = PageAdminForm - unknown_fields = ['template_key', 'parent', 'override_url', 'redirect_to'] fieldset_insertion_index = 2 fieldsets = [ (None, { @@ -41,7 +40,7 @@ class Media: }), (_('Other options'), { 'classes': ['collapse'], - 'fields': unknown_fields, + 'fields': ['template_key', 'parent', 'override_url', 'redirect_to'], }), # <-- insertion point, extensions appear here, see insertion_index above item_editor.FEINCMS_CONTENT_FIELDSET, @@ -82,9 +81,12 @@ def __init__(self, model, admin_site): present_fields = flatten_fieldsets(self.fieldsets) for f in self.model._meta.fields: - if not f.name.startswith('_') and not f.name in ('id', 'lft', 'rght', 'tree_id', 'level') and \ - not f.auto_created and not f.name in present_fields and f.editable: - self.unknown_fields.append(f.name) + if (not f.name.startswith('_') + and not f.name in ('id', 'lft', 'rght', 'tree_id', 'level') + and not f.auto_created + and not f.name in present_fields + and f.editable): + self.fieldsets[1][1]['fields'].append(f.name) if not f.editable: self.readonly_fields.append(f.name) From 23da79e6b69d070f8b35c356c90b3d9cb2d7a114 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 9 Nov 2013 14:56:26 +0100 Subject: [PATCH 0821/1590] Deprecate the automatic collection of model fields --- docs/deprecation.rst | 9 +++++++++ docs/releases/1.8.rst | 10 ++++++++++ feincms/module/page/modeladmins.py | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index 63fa9f61f..ab9043f38 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -85,3 +85,12 @@ will be issued for at least two releases. removed. * ``Page.setup_request()`` does not do anything anymore and will be removed. + + +1.9 +=== + +* Fields added through page extensions which haven't been explicitly added + to the page model admin using ``modeladmin.add_extension_options`` will + disappear from the admin interface. The automatic collection of fields + will be removed. diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index d50595598..1e67a667c 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -84,6 +84,16 @@ Removal of deprecated features anything for some time now. +New deprecations +================ + +* Page extensions should start explicitly adding their fields to the + administration interface using ``modeladmin.add_extension_options``. + FeinCMS v1.8 will warn about fields collected automatically, the next + release will not add unknown fields to the administration interface + anymore. + + Notable features and improvements ================================= diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 47458d2e6..f9021123a 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -4,6 +4,8 @@ from __future__ import absolute_import +import warnings + from django.conf import settings as django_settings from django.core.exceptions import PermissionDenied from django.contrib.contenttypes.models import ContentType @@ -87,6 +89,12 @@ def __init__(self, model, admin_site): and not f.name in present_fields and f.editable): self.fieldsets[1][1]['fields'].append(f.name) + warnings.warn( + 'Automatically adding %r to %r.fieldsets. This behavior' + ' is deprecated. Use add_extension_options yourself if' + ' you want fields to appear in the page' + ' administration.' % (f.name, self), + DeprecationWarning) if not f.editable: self.readonly_fields.append(f.name) From eb66f4bf776ee2fe525edd402d84249eea8b0d49 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 9 Nov 2013 15:03:10 +0100 Subject: [PATCH 0822/1590] Port symlinks and site extensions to feincms.extensions --- feincms/module/page/extensions/sites.py | 18 ++++++----- feincms/module/page/extensions/symlinks.py | 36 +++++++++++++--------- feincms/module/page/modeladmins.py | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index 34f13cac6..9083a7b1f 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -3,6 +3,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions from feincms.module.page.models import PageManager @@ -10,12 +11,15 @@ def current_site(queryset): return queryset.filter(site=Site.objects.get_current()) -def register(cls, admin_cls): - cls.add_to_class('site', - models.ForeignKey(Site, verbose_name=_('Site'), - default=settings.SITE_ID)) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('site', + models.ForeignKey(Site, verbose_name=_('Site'), + default=settings.SITE_ID)) - PageManager.add_to_active_filters(current_site, key='current_site') + PageManager.add_to_active_filters(current_site, key='current_site') - admin_cls.list_display.extend(['site']) - admin_cls.list_filter.extend(['site']) + def handle_modeladmin(self, modeladmin): + modeladmin.list_display.extend(['site']) + modeladmin.list_filter.extend(['site']) + modeladmin.add_extension_options('site') diff --git a/feincms/module/page/extensions/symlinks.py b/feincms/module/page/extensions/symlinks.py index 722ee4220..4e5e2d82f 100644 --- a/feincms/module/page/extensions/symlinks.py +++ b/feincms/module/page/extensions/symlinks.py @@ -6,23 +6,31 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions from feincms._internal import monkeypatch_property -def register(cls, admin_cls): - cls.add_to_class('symlinked_page', models.ForeignKey('self', blank=True, null=True, - related_name='%(app_label)s_%(class)s_symlinks', - verbose_name=_('symlinked page'), - help_text=_('All content is inherited from this page if given.'))) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('symlinked_page', models.ForeignKey( + 'self', + blank=True, + null=True, + related_name='%(app_label)s_%(class)s_symlinks', + verbose_name=_('symlinked page'), + help_text=_('All content is inherited from this page if given.'))) - @monkeypatch_property(cls) - def content(self): - if not hasattr(self, '_content_proxy'): - if self.symlinked_page: - self._content_proxy = self.content_proxy_class(self.symlinked_page) - else: - self._content_proxy = self.content_proxy_class(self) + @monkeypatch_property(self.model) + def content(self): + if not hasattr(self, '_content_proxy'): + if self.symlinked_page: + self._content_proxy = self.content_proxy_class( + self.symlinked_page) + else: + self._content_proxy = self.content_proxy_class(self) - return self._content_proxy + return self._content_proxy - admin_cls.raw_id_fields.append('symlinked_page') + def handle_modeladmin(self, modeladmin): + modeladmin.raw_id_fields.append('symlinked_page') + modeladmin.add_extension_options('symlinked_page') diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index f9021123a..ddbf3e17d 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -93,7 +93,7 @@ def __init__(self, model, admin_site): 'Automatically adding %r to %r.fieldsets. This behavior' ' is deprecated. Use add_extension_options yourself if' ' you want fields to appear in the page' - ' administration.' % (f.name, self), + ' administration.' % (f.name, self.__class__), DeprecationWarning) if not f.editable: self.readonly_fields.append(f.name) From 5f03bcd52347260351b7f4f987e2c1404fd989a1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 9 Nov 2013 15:24:54 +0100 Subject: [PATCH 0823/1590] Convert all bundled extensions to feincms.extensions --- docs/deprecation.rst | 4 + docs/releases/1.8.rst | 4 + feincms/extensions.py | 7 +- feincms/module/blog/extensions/tags.py | 17 ++- .../module/blog/extensions/translations.py | 90 ++++++++------- feincms/module/extensions/changedate.py | 28 +++-- feincms/module/extensions/ct_tracker.py | 17 +-- feincms/module/extensions/datepublisher.py | 105 +++++++++--------- feincms/module/extensions/featured.py | 20 ++-- feincms/module/extensions/seo.py | 29 +++-- feincms/module/page/extensions/excerpt.py | 21 ++-- .../module/page/extensions/relatedpages.py | 27 +++-- feincms/module/page/extensions/titles.py | 83 ++++++++------ 13 files changed, 264 insertions(+), 188 deletions(-) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index ab9043f38..e8cd6d6af 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -94,3 +94,7 @@ will be issued for at least two releases. to the page model admin using ``modeladmin.add_extension_options`` will disappear from the admin interface. The automatic collection of fields will be removed. + +* All extensions should inherit from ``feincms.extensions.Extension``. + Support for ``register(cls, admin_cls)``-style functions will be removed + in FeinCMS v1.9. diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index 1e67a667c..5330a7657 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -93,6 +93,10 @@ New deprecations release will not add unknown fields to the administration interface anymore. +* All extensions should inherit from ``feincms.extensions.Extension``. + Support for ``register(cls, admin_cls)``-style functions will be removed + in FeinCMS v1.9. + Notable features and improvements ================================= diff --git a/feincms/extensions.py b/feincms/extensions.py index e0e44869f..7b43b0a85 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -74,7 +74,12 @@ def register_extensions(cls, *extensions): if hasattr(extension, 'handle_model'): cls._extensions.append(extension(cls)) else: - cls._extensions.append(LegacyExtension(cls, extension=extension)) + warning.warn( + '%r is a extension in legacy format.' + ' Support for legacy extensions will be removed in' + ' FeinCMS v1.9. Convert your extensions to' + ' feincms.extensions.Extension now.' % extension, + DeprecationWarning) class Extension(object): diff --git a/feincms/module/blog/extensions/tags.py b/feincms/module/blog/extensions/tags.py index 2838d1b3c..5df1fa143 100644 --- a/feincms/module/blog/extensions/tags.py +++ b/feincms/module/blog/extensions/tags.py @@ -4,13 +4,20 @@ from django.utils.translation import ugettext_lazy as _ +from feincms import extensions + import tagging from tagging.fields import TagField -def register(cls, admin_cls): - cls.add_to_class('tags', TagField(_('tags'))) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('tags', TagField(_('tags'))) + + # use another name for the tag descriptor See + # http://code.google.com/p/django-tagging/issues/detail?id=95 for the + # reason why + tagging.register(self.model, tag_descriptor_attr='etags') - # use another name for the tag descriptor - # See http://code.google.com/p/django-tagging/issues/detail?id=95 for the reason why - tagging.register(cls, tag_descriptor_attr='etags') + def handle_modeladmin(self, modeladmin): + modeladmin.add_extension_options('tags') diff --git a/feincms/module/blog/extensions/translations.py b/feincms/module/blog/extensions/translations.py index 97cd24404..72f62251a 100644 --- a/feincms/module/blog/extensions/translations.py +++ b/feincms/module/blog/extensions/translations.py @@ -10,44 +10,52 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ - -def register(cls, admin_cls): - primary_language = settings.LANGUAGES[0][0] - - cls.add_to_class('language', models.CharField(_('language'), max_length=10, - choices=settings.LANGUAGES)) - cls.add_to_class('translation_of', models.ForeignKey('self', - blank=True, null=True, verbose_name=_('translation of'), - related_name='translations', - limit_choices_to={'language': primary_language}, - help_text=_('Leave this empty for entries in the primary language.') - )) - - def available_translations(self): - if self.language == primary_language: - return self.translations.all() - elif self.translation_of: - return [self.translation_of] + list(self.translation_of.translations.exclude( - language=self.language)) - else: - return [] - - cls.available_translations = available_translations - - def available_translations_admin(self): - translations = self.available_translations() - - return u', '.join( - u'%s' % (page.id, page.language.upper()) for page in translations) - - available_translations_admin.allow_tags = True - available_translations_admin.short_description = _('available translations') - cls.available_translations_admin = available_translations_admin - - if getattr(admin_cls, 'fieldsets'): - admin_cls.fieldsets[0][1]['fields'].extend(['language']) - - admin_cls.list_display += ('language', 'available_translations_admin') - admin_cls.list_filter += ('language',) - - admin_cls.raw_id_fields.append('translation_of') +from feincms import extensions + + +class Extension(extensions.Extension): + def handle_model(self): + primary_language = settings.LANGUAGES[0][0] + + self.model.add_to_class('language', models.CharField( + _('language'), max_length=10, + choices=settings.LANGUAGES)) + self.model.add_to_class('translation_of', models.ForeignKey('self', + blank=True, null=True, verbose_name=_('translation of'), + related_name='translations', + limit_choices_to={'language': primary_language}, + help_text=_('Leave this empty for entries in the primary language.') + )) + + def available_translations(self): + if self.language == primary_language: + return self.translations.all() + elif self.translation_of: + return [self.translation_of] + list( + self.translation_of.translations.exclude( + language=self.language)) + else: + return [] + + self.model.available_translations = available_translations + + def available_translations_admin(self): + translations = self.available_translations() + + return u', '.join( + u'%s' % ( + page.id, page.language.upper() + ) for page in translations) + + available_translations_admin.allow_tags = True + available_translations_admin.short_description = _('available translations') + self.model.available_translations_admin = available_translations_admin + + def handle_modeladmin(self, modeladmin): + modeladmin.add_extension_options('language') + + modeladmin.list_display.extend(( + 'language', 'available_translations_admin')) + modeladmin.list_filter.extend(('language',)) + + modeladmin.raw_id_fields.append('translation_of') diff --git a/feincms/module/extensions/changedate.py b/feincms/module/extensions/changedate.py index ec2b4d624..89a3cd13a 100644 --- a/feincms/module/extensions/changedate.py +++ b/feincms/module/extensions/changedate.py @@ -12,6 +12,8 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ +from feincms import extensions + # ------------------------------------------------------------------------ def pre_save_handler(sender, instance, **kwargs): @@ -31,19 +33,21 @@ def dt_to_utc_timestamp(dt): return int(mktime(dt.timetuple())) -def register(cls, admin_cls): - cls.add_to_class('creation_date', - models.DateTimeField(_('creation date'), null=True, editable=False)) - cls.add_to_class('modification_date', - models.DateTimeField(_('modification date'), null=True, editable=False)) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('creation_date', + models.DateTimeField(_('creation date'), null=True, editable=False)) + self.model.add_to_class('modification_date', + models.DateTimeField(_('modification date'), null=True, editable=False)) - if hasattr(cls, 'cache_key_components'): - cls.cache_key_components.append( - lambda page: page.modification_date and str(dt_to_utc_timestamp(page.modification_date))) + if hasattr(self.model, 'cache_key_components'): + self.model.cache_key_components.append( + lambda page: page.modification_date and str( + dt_to_utc_timestamp(page.modification_date))) - cls.last_modified = lambda p: p.modification_date + self.model.last_modified = lambda p: p.modification_date - pre_save.connect(pre_save_handler, sender=cls) + pre_save.connect(pre_save_handler, sender=self.model) # ------------------------------------------------------------------------ @@ -57,7 +61,9 @@ def last_modified_response_processor(page, request, response): # If we already have a Last-Modified, take the later one last_modified = dt_to_utc_timestamp(page.last_modified()) if response.has_header('Last-Modified'): - last_modified = max(last_modified, mktime_tz(parsedate_tz(response['Last-Modified']))) + last_modified = max( + last_modified, + mktime_tz(parsedate_tz(response['Last-Modified']))) response['Last-Modified'] = http_date(last_modified) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 58b35b797..a8bd06ea9 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -21,6 +21,7 @@ from django.db.models.signals import class_prepared, post_save, pre_save from django.utils.translation import ugettext_lazy as _ +from feincms import extensions from feincms.contrib.fields import JSONField from feincms.models import ContentProxy @@ -140,12 +141,14 @@ def single_pre_save_handler(sender, instance, **kwargs): # ------------------------------------------------------------------------ -def register(cls, admin_cls): - cls.add_to_class('_ct_inventory', JSONField(_('content types'), editable=False, blank=True, null=True)) - cls.content_proxy_class = TrackerContentProxy - - pre_save.connect(single_pre_save_handler, sender=cls) - if hasattr(cls, 'get_descendants'): - post_save.connect(tree_post_save_handler, sender=cls) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('_ct_inventory', JSONField( + _('content types'), editable=False, blank=True, null=True)) + self.model.content_proxy_class = TrackerContentProxy + + pre_save.connect(single_pre_save_handler, sender=self.model) + if hasattr(self.model, 'get_descendants'): + post_save.connect(tree_post_save_handler, sender=self.model) # ------------------------------------------------------------------------ diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index f05c6f45d..267ecb44f 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -16,6 +16,8 @@ from django.utils.cache import patch_response_headers from django.utils.translation import ugettext_lazy as _ +from feincms import extensions + # ------------------------------------------------------------------------ def format_date(d, if_none=''): @@ -74,55 +76,58 @@ def datepublisher_response_processor(page, request, response): # ------------------------------------------------------------------------ -def register(cls, admin_cls): - cls.add_to_class('publication_date', - models.DateTimeField(_('publication date'), default=granular_now)) - cls.add_to_class('publication_end_date', - models.DateTimeField(_('publication end date'), - blank=True, null=True, - help_text=_('Leave empty if the entry should stay active forever.'))) - cls.add_to_class('latest_children', latest_children) - - # Patch in rounding the pub and pub_end dates on save - orig_save = cls.save - - def granular_save(obj, *args, **kwargs): - if obj.publication_date: - obj.publication_date = granular_now(obj.publication_date) - if obj.publication_end_date: - obj.publication_end_date = granular_now(obj.publication_end_date) - orig_save(obj, *args, **kwargs) - cls.save = granular_save - - # Append publication date active check - if hasattr(cls._default_manager, 'add_to_active_filters'): - cls._default_manager.add_to_active_filters( - Q(publication_date__lte=granular_now) & - (Q(publication_end_date__isnull=True) | - Q(publication_end_date__gt=granular_now)), - key='datepublisher') - - # Processor to patch up response headers for expiry date - cls.register_response_processor(datepublisher_response_processor) - - def datepublisher_admin(self): - return u'%s – %s' % ( - format_date(self.publication_date), - format_date(self.publication_end_date, '∞'), - ) - datepublisher_admin.allow_tags = True - datepublisher_admin.short_description = _('visible from - to') - - cls.datepublisher_admin = datepublisher_admin - try: - pos = admin_cls.list_display.index('is_visible_admin') - except ValueError: - pos = len(admin_cls.list_display) - - admin_cls.list_display.insert(pos + 1, 'datepublisher_admin') - - admin_cls.add_extension_options(_('Date-based publishing'), { - 'fields': ['publication_date', 'publication_end_date'], - }) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('publication_date', + models.DateTimeField(_('publication date'), default=granular_now)) + self.model.add_to_class('publication_end_date', + models.DateTimeField(_('publication end date'), + blank=True, null=True, + help_text=_('Leave empty if the entry should stay active forever.'))) + self.model.add_to_class('latest_children', latest_children) + + # Patch in rounding the pub and pub_end dates on save + orig_save = self.model.save + + def granular_save(obj, *args, **kwargs): + if obj.publication_date: + obj.publication_date = granular_now(obj.publication_date) + if obj.publication_end_date: + obj.publication_end_date = granular_now(obj.publication_end_date) + orig_save(obj, *args, **kwargs) + self.model.save = granular_save + + # Append publication date active check + if hasattr(self.model._default_manager, 'add_to_active_filters'): + self.model._default_manager.add_to_active_filters( + Q(publication_date__lte=granular_now) & + (Q(publication_end_date__isnull=True) | + Q(publication_end_date__gt=granular_now)), + key='datepublisher') + + # Processor to patch up response headers for expiry date + self.model.register_response_processor(datepublisher_response_processor) + + def handle_modeladmin(self, modeladmin): + def datepublisher_admin(self, obj): + return u'%s – %s' % ( + format_date(obj.publication_date), + format_date(obj.publication_end_date, '∞'), + ) + datepublisher_admin.allow_tags = True + datepublisher_admin.short_description = _('visible from - to') + + modeladmin.__class__.datepublisher_admin = datepublisher_admin + + try: + pos = modeladmin.list_display.index('is_visible_admin') + except ValueError: + pos = len(modeladmin.list_display) + + modeladmin.list_display.insert(pos + 1, 'datepublisher_admin') + + modeladmin.add_extension_options(_('Date-based publishing'), { + 'fields': ['publication_date', 'publication_end_date'], + }) # ------------------------------------------------------------------------ diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index a41e42772..d130aa855 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -5,14 +5,18 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions -def register(cls, admin_cls): - cls.add_to_class('featured', models.BooleanField(_('featured'))) - if hasattr(cls, 'cache_key_components'): - cls.cache_key_components.append(lambda page: page.featured) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('featured', models.BooleanField(_('featured'))) - admin_cls.add_extension_options(_('Featured'), { - 'fields': ('featured',), - 'classes': ('collapse',), - }) + if hasattr(self.model, 'cache_key_components'): + self.model.cache_key_components.append(lambda page: page.featured) + + def handle_modeladmin(self, modeladmin): + modeladmin.add_extension_options(_('Featured'), { + 'fields': ('featured',), + 'classes': ('collapse',), + }) diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index cbc1af58e..f3aa724de 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -5,21 +5,26 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions -def register(cls, admin_cls): - cls.add_to_class('meta_keywords', models.TextField(_('meta keywords'), - blank=True, - help_text=_('Keywords are ignored by most search engines.'))) - cls.add_to_class('meta_description', models.TextField(_('meta description'), - blank=True, - help_text=_('This text is displayed on the search results page. ' - 'It is however not used for the SEO ranking. ' - 'Text longer than 140 characters is truncated.'))) - if admin_cls: - admin_cls.search_fields.extend(['meta_keywords', 'meta_description']) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('meta_keywords', models.TextField( + _('meta keywords'), + blank=True, + help_text=_('Keywords are ignored by most search engines.'))) + self.model.add_to_class('meta_description', models.TextField( + _('meta description'), + blank=True, + help_text=_('This text is displayed on the search results page. ' + 'It is however not used for the SEO ranking. ' + 'Text longer than 140 characters is truncated.'))) - admin_cls.add_extension_options(_('Search engine optimization'), { + def handle_modeladmin(self, modeladmin): + modeladmin.search_fields.extend(['meta_keywords', 'meta_description']) + + modeladmin.add_extension_options(_('Search engine optimization'), { 'fields': ('meta_keywords', 'meta_description'), 'classes': ('collapse',), }) diff --git a/feincms/module/page/extensions/excerpt.py b/feincms/module/page/extensions/excerpt.py index 0350e5076..3861a7a1f 100644 --- a/feincms/module/page/extensions/excerpt.py +++ b/feincms/module/page/extensions/excerpt.py @@ -5,12 +5,19 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions -def register(cls, admin_cls): - cls.add_to_class('excerpt', models.TextField(_('excerpt'), blank=True, - help_text=_('Add a brief excerpt summarizing the content of this page.'))) - admin_cls.add_extension_options(_('Excerpt'), { - 'fields': ('excerpt',), - 'classes': ('collapse',), - }) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('excerpt', models.TextField( + _('excerpt'), + blank=True, + help_text=_('Add a brief excerpt summarizing the content' + ' of this page.'))) + + def handle_modeladmin(self, modeladmin): + modeladmin.add_extension_options(_('Excerpt'), { + 'fields': ('excerpt',), + 'classes': ('collapse',), + }) diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index d54b42b1f..848d58cd1 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -5,18 +5,25 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions from feincms.module.page.models import Page -def register(cls, admin_cls): - cls.add_to_class('related_pages', models.ManyToManyField(Page, blank=True, - related_name='%(app_label)s_%(class)s_related', - null=True, help_text=_('Select pages that should be listed as related content.'))) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('related_pages', models.ManyToManyField( + Page, + blank=True, + null=True, + related_name='%(app_label)s_%(class)s_related', + help_text=_('Select pages that should be listed as related content.'))) - admin_cls.filter_horizontal = list(getattr(admin_cls, 'filter_horizontal', ())) - admin_cls.filter_horizontal.append('related_pages') + def handle_modeladmin(self, modeladmin): + modeladmin.filter_horizontal = list( + getattr(admin_cls, 'filter_horizontal', ())) + modeladmin.filter_horizontal.append('related_pages') - admin_cls.add_extension_options(_('Related pages'), { - 'fields': ('related_pages',), - 'classes': ('collapse',), - }) + modeladmin.add_extension_options(_('Related pages'), { + 'fields': ('related_pages',), + 'classes': ('collapse',), + }) diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index 5bfab7c83..e5e63ab51 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -7,42 +7,53 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from feincms import extensions from feincms._internal import monkeypatch_property -def register(cls, admin_cls): - cls.add_to_class('_content_title', models.TextField(_('content title'), blank=True, - help_text=_('The first line is the main title, the following lines are subtitles.'))) - cls.add_to_class('_page_title', models.CharField(_('page title'), max_length=69, blank=True, - help_text=_('Page title for browser window. Same as title by default. ' - 'Must not be longer than 70 characters.'))) - - @monkeypatch_property(cls) - def page_title(self): - """ - Use this for the browser window (-tag in the <head> of the HTML document) - """ - - if self._page_title: - return self._page_title - return self.content_title - - @monkeypatch_property(cls) - def content_title(self): - """ - This should be used f.e. for the <h1>-tag - """ - - if not self._content_title: - return self.title - - return self._content_title.splitlines()[0] - - @monkeypatch_property(cls) - def content_subtitle(self): - return u'\n'.join(self._content_title.splitlines()[1:]) - - admin_cls.add_extension_options(_('Titles'), { - 'fields': ('_content_title', '_page_title'), - 'classes': ('collapse',), - }) +class Extension(extensions.Extension): + def handle_model(self): + self.model.add_to_class('_content_title', models.TextField( + _('content title'), + blank=True, + help_text=_('The first line is the main title, the following' + ' lines are subtitles.'))) + + self.model.add_to_class('_page_title', models.CharField( + _('page title'), + max_length=69, + blank=True, + help_text=_('Page title for browser window. Same as title by' + 'default. Must not be longer than 70 characters.'))) + + @monkeypatch_property(self.model) + def page_title(self): + """ + Use this for the browser window (<title>-tag in the <head> of the + HTML document) + """ + + if self._page_title: + return self._page_title + return self.content_title + + @monkeypatch_property(self.model) + def content_title(self): + """ + This should be used f.e. for the <h1>-tag + """ + + if not self._content_title: + return self.title + + return self._content_title.splitlines()[0] + + @monkeypatch_property(self.model) + def content_subtitle(self): + return u'\n'.join(self._content_title.splitlines()[1:]) + + def handle_modeladmin(self, modeladmin): + modeladmin.add_extension_options(_('Titles'), { + 'fields': ('_content_title', '_page_title'), + 'classes': ('collapse',), + }) From 298ad0f116bbe2670427b878887014bb2c786498 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 9 Nov 2013 15:31:16 +0100 Subject: [PATCH 0824/1590] Add a snippet regarding singleton templates to the release notes --- docs/releases/1.8.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index 5330a7657..65e658a5f 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -22,7 +22,10 @@ The testsuite runs through on Python 3.3. Singleton templates =================== -TODO document this. +Templates can be defined to be singletons, which means that those templates +can only occur once on a whole site. The page module additionally allows +specifying that singleton templates must not have any children, and also +that the page cannot be deleted. Dependencies are automatically installed From f544cc5bdb9c04c174af407cba5db3a581699fee Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 10 Nov 2013 18:00:25 +0100 Subject: [PATCH 0825/1590] Regenerate AUTHORS --- AUTHORS | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/AUTHORS b/AUTHORS index a62c1c1d6..e7fa8eec3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,60 +6,61 @@ The authors of FeinCMS are: * Simon Meers * Bojan Mihelac * Simon Bächler -* Bjorn Post * Stephan Jaekel +* Bjorn Post * Julien Phalip * Daniel Renz -* Matt Dawson -* Simon Schürpf * Skylar Saveland +* Simon Schürpf +* Matt Dawson * Stefan Reinhard +* Simon Schmid * Marc Egli * Psyton -* Simon Schmid * Greg Turner +* Maarten van Gompel (proycon) * Bjarni Thorisson * Greg Taylor -* Maarten van Gompel (proycon) -* Antoni Aloy -* Jonas * Julian Bez +* Jonas +* Antoni Aloy * Urs Breton +* Sander van Leeuwen +* Nico Echaniz * Afonso Fernández Nogueira +* Toby White +* Charlie Denton +* Vítor Figueiró * Marc Tamlyn * Martin Mahner * Max Peterson -* Nico Echaniz -* Sander van Leeuwen -* Toby White -* Vítor Figueiró -* Andrew D. Ball * Brian Macdonald +* Maarten Draijer * Eric Delord * Gabriel Kovacs -* Maarten Draijer +* adsworth +* Andrew D. Ball * Torkn -* Cellarosi Marco -* Fabian Germann +* Raphael Jasjukaitis +* Michael Bashkirov * Fabian Vogler +* Fabian Germann +* Wil Tan +* Vaclav Klecanda +* tayg * Håvard Grimelid -* Maciek Szczesniak -* Marco Fucci -* Michael Bashkirov +* Cellarosi Marco * Mikhail Korobov -* Raphael Jasjukaitis +* Maciek Szczesniak * Richard A -* Vaclav Klecanda -* Wil Tan -* adsworth -* tayg +* Marco Fucci +* Tobias Haffner * Alen Mujezinovic * Alex Kamedov * Andi Albrecht * Andrey Popelo * Andrin Heusser * Anshuman Bhaduri -* Charlie Denton * Daniele Procida * Darryl Woods * David Evans @@ -84,6 +85,6 @@ The authors of FeinCMS are: * Rico Moorman * Sebastian Hillig * Silvan Spross -* Tobias Haffner * Valtron * Wouter van der Graaf +* svleeuwen From 5810d4987180bb98f3425cd64fb46938242a7085 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 11 Nov 2013 10:11:20 +1100 Subject: [PATCH 0826/1590] Decouple PageSitemap from the One Page Model. See #241. --- feincms/module/page/sitemap.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index 89d22c760..eef72264f 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -2,19 +2,18 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from django.conf import settings from django.db.models import Max +from django.db.models import get_model from django.contrib.sitemaps import Sitemap -from feincms.module.page.models import Page - - # ------------------------------------------------------------------------ class PageSitemap(Sitemap): """ The PageSitemap can be used to automatically generate sitemap.xml files for submission to index engines. See http://www.sitemaps.org/ for details. """ - def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset=None, filter=None, extended_navigation=False, *args, **kwargs): + def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset=None, filter=None, extended_navigation=False, page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL, *args, **kwargs): """ The PageSitemap accepts the following parameters for customisation of the resulting sitemap.xml output: @@ -42,6 +41,7 @@ def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset if queryset is not None: self.queryset = queryset else: + Page = get_model(*page_model.split('.')) self.queryset = Page.objects.active() def items(self): From d612457f70792e045cea01dddc23b800505fe272 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Tue, 12 Nov 2013 20:20:03 +1100 Subject: [PATCH 0827/1590] import settings from feincms module in page.sitemap --- feincms/module/page/sitemap.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index eef72264f..fa1f640a7 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -2,11 +2,12 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from django.conf import settings from django.db.models import Max from django.db.models import get_model from django.contrib.sitemaps import Sitemap +from feincms import settings + # ------------------------------------------------------------------------ class PageSitemap(Sitemap): """ From b3b2eb96a20c0c332267cab8d43535f6be9171b4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 11:51:34 +0100 Subject: [PATCH 0828/1590] FeinCMS v1.8.0 --- docs/releases/1.8.rst | 6 +++--- feincms/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index 65e658a5f..c02d7edf3 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -1,6 +1,6 @@ -==================================== -FeinCMS 1.8 release notes (upcoming) -==================================== +========================= +FeinCMS 1.8 release notes +========================= Welcome to FeinCMS 1.8! diff --git a/feincms/__init__.py b/feincms/__init__.py index f4baaca4d..96c63ae9f 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 8, 0, 'pre') +VERSION = (1, 8, 0) __version__ = '.'.join(map(str, VERSION)) From 3dcb8f000d3a4ee55808b6b937ed3300eca18af3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 11:55:23 +0100 Subject: [PATCH 0829/1590] Open the 1.9 branch --- docs/index.rst | 1 + docs/releases/1.9.rst | 46 +++++++++++++++++++++++++++++++++++++++++++ feincms/__init__.py | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 docs/releases/1.9.rst diff --git a/docs/index.rst b/docs/index.rst index 658ff44a9..434683fb0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -92,6 +92,7 @@ Releases .. toctree:: :maxdepth: 1 + releases/1.9 releases/1.8 releases/1.7 releases/1.6 diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst new file mode 100644 index 000000000..4c88e6f2c --- /dev/null +++ b/docs/releases/1.9.rst @@ -0,0 +1,46 @@ +==================================== +FeinCMS 1.9 release notes (upcoming) +==================================== + +Welcome to FeinCMS 1.9! + + +Major feature 1 +=============== + + +Backwards-incompatible changes +============================== + + +Removal of deprecated features +------------------------------ + + +New deprecations +================ + +* Page extensions should start explicitly adding their fields to the + administration interface using ``modeladmin.add_extension_options``. + FeinCMS v1.8 will warn about fields collected automatically, the next + release will not add unknown fields to the administration interface + anymore. + +* All extensions should inherit from ``feincms.extensions.Extension``. + Support for ``register(cls, admin_cls)``-style functions will be removed + in FeinCMS v1.9. + + +Notable features and improvements +================================= + + +Bugfixes +======== + + +Compatibility with Django and other apps +======================================== + +FeinCMS 1.8 requires Django 1.4 or better. The testsuite is successfully run +against Django 1.4, 1.5, 1.6 and the upcoming 1.7. diff --git a/feincms/__init__.py b/feincms/__init__.py index 96c63ae9f..e9670fdeb 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 8, 0) +VERSION = (1, 9, 0, 'pre') __version__ = '.'.join(map(str, VERSION)) From bc9ff8318b8eace9925e204fb5c536ed23a2cda3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 11:59:46 +0100 Subject: [PATCH 0830/1590] This line should NOT have been removed --- feincms/extensions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/extensions.py b/feincms/extensions.py index 7b43b0a85..a64424f0d 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -80,6 +80,7 @@ def register_extensions(cls, *extensions): ' FeinCMS v1.9. Convert your extensions to' ' feincms.extensions.Extension now.' % extension, DeprecationWarning) + cls._extensions.append(LegacyExtension(cls, extension=extension)) class Extension(object): From 386511b1f14c072bf91f99dd9ccf238e41507048 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 12:01:27 +0100 Subject: [PATCH 0831/1590] Remove support for legacy extensions --- docs/releases/1.9.rst | 8 +++--- feincms/extensions.py | 67 ++----------------------------------------- 2 files changed, 6 insertions(+), 69 deletions(-) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index 4c88e6f2c..c8468f133 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -16,6 +16,10 @@ Backwards-incompatible changes Removal of deprecated features ------------------------------ +* All extensions should inherit from ``feincms.extensions.Extension``. + The support for ``register(cls, admin_cls)``-style functions has been + removed. + New deprecations ================ @@ -26,10 +30,6 @@ New deprecations release will not add unknown fields to the administration interface anymore. -* All extensions should inherit from ``feincms.extensions.Extension``. - Support for ``register(cls, admin_cls)``-style functions will be removed - in FeinCMS v1.9. - Notable features and improvements ================================= diff --git a/feincms/extensions.py b/feincms/extensions.py index a64424f0d..591d6106f 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -74,13 +74,8 @@ def register_extensions(cls, *extensions): if hasattr(extension, 'handle_model'): cls._extensions.append(extension(cls)) else: - warning.warn( - '%r is a extension in legacy format.' - ' Support for legacy extensions will be removed in' - ' FeinCMS v1.9. Convert your extensions to' - ' feincms.extensions.Extension now.' % extension, - DeprecationWarning) - cls._extensions.append(LegacyExtension(cls, extension=extension)) + raise ImproperlyConfigured( + '%r is an invalid extension.' % extension) class Extension(object): @@ -108,64 +103,6 @@ def _ensure_list(cls, attribute): setattr(cls, attribute, list(value)) -class LegacyExtension(Extension): - """ - Wrapper for legacy extensions - """ - - #: Legacy extension function - extension = None - - def handle_model(self): - self.fieldsets = [] - self.filter_horizontal = [] - self.filter_vertical = [] - self.list_display = [] - self.list_filter = [] - self.raw_id_fields = [] - self.search_fields = [] - - self.extension_options = [] - self.known_keys = self.__dict__.keys() - - self.extension(self.model, self) - - def handle_modeladmin(self, modeladmin): - if self.fieldsets: - _ensure_list(modeladmin, 'fieldsets') - modeladmin.fieldsets.extend(self.fieldsets) - if self.filter_horizontal: - _ensure_list(modeladmin, 'filter_horizontal') - modeladmin.filter_horizontal.extend(self.filter_horizontal) - if self.filter_vertical: - _ensure_list(modeladmin, 'filter_vertical') - modeladmin.filter_vertical.extend(self.filter_vertical) - if self.list_display: - _ensure_list(modeladmin, 'list_display') - modeladmin.list_display.extend(self.list_display) - if self.list_filter: - _ensure_list(modeladmin, 'list_filter') - modeladmin.list_filter.extend(self.list_filter) - if self.raw_id_fields: - _ensure_list(modeladmin, 'raw_id_fields') - modeladmin.raw_id_fields.extend(self.raw_id_fields) - if self.search_fields: - _ensure_list(modeladmin, 'search_fields') - modeladmin.search_fields.extend(self.search_fields) - - if self.extension_options: - for f in self.extension_options: - modeladmin.add_extension_options(*f) - - for key, value in self.__dict__.items(): - if key not in self.known_keys: - setattr(modeladmin.__class__, key, value) - - def add_extension_options(self, *f): - if f: - self.extension_options.append(f) - - class ExtensionModelAdmin(admin.ModelAdmin): def __init__(self, *args, **kwargs): super(ExtensionModelAdmin, self).__init__(*args, **kwargs) From 75b57f18bf61fa29cb6fd8769d3dd16ee04fe552 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 12:03:52 +0100 Subject: [PATCH 0832/1590] Remove the automatic addition of unknown fields to the page admin fieldset --- docs/releases/1.9.rst | 10 +++++----- feincms/module/page/modeladmins.py | 24 ------------------------ 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index c8468f133..f28007ae0 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -20,15 +20,15 @@ Removal of deprecated features The support for ``register(cls, admin_cls)``-style functions has been removed. +* Unknown page model fields (for example those added through page extensions) + aren't added to the administration interface anymore. Use + ``modeladmin.add_extension_options`` if you want extension fields to + appear. + New deprecations ================ -* Page extensions should start explicitly adding their fields to the - administration interface using ``modeladmin.add_extension_options``. - FeinCMS v1.8 will warn about fields collected automatically, the next - release will not add unknown fields to the administration interface - anymore. Notable features and improvements diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index ddbf3e17d..8e33a9f97 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -74,30 +74,6 @@ def __init__(self, model, admin_site): super(PageAdmin, self).__init__(model, admin_site) - # The use of fieldsets makes only fields explicitly listed in there - # actually appear in the admin form. However, extensions should not be - # aware that there is a fieldsets structure and even less modify it; - # we therefore enumerate all of the model's field and forcibly add them - # to the last section in the admin. That way, nobody is left behind. - from django.contrib.admin.util import flatten_fieldsets - present_fields = flatten_fieldsets(self.fieldsets) - - for f in self.model._meta.fields: - if (not f.name.startswith('_') - and not f.name in ('id', 'lft', 'rght', 'tree_id', 'level') - and not f.auto_created - and not f.name in present_fields - and f.editable): - self.fieldsets[1][1]['fields'].append(f.name) - warnings.warn( - 'Automatically adding %r to %r.fieldsets. This behavior' - ' is deprecated. Use add_extension_options yourself if' - ' you want fields to appear in the page' - ' administration.' % (f.name, self.__class__), - DeprecationWarning) - if not f.editable: - self.readonly_fields.append(f.name) - in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) def get_readonly_fields(self, request, obj=None): From 379b2a5a42e96b1e9a0544b1e0eb5898d24045e1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 12:05:00 +0100 Subject: [PATCH 0833/1590] Fix flake8 problems --- feincms/extensions.py | 2 +- feincms/module/page/extensions/relatedpages.py | 2 +- feincms/module/page/sitemap.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index a64424f0d..9d67349e2 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -74,7 +74,7 @@ def register_extensions(cls, *extensions): if hasattr(extension, 'handle_model'): cls._extensions.append(extension(cls)) else: - warning.warn( + warnings.warn( '%r is a extension in legacy format.' ' Support for legacy extensions will be removed in' ' FeinCMS v1.9. Convert your extensions to' diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 848d58cd1..0e80ca885 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -20,7 +20,7 @@ def handle_model(self): def handle_modeladmin(self, modeladmin): modeladmin.filter_horizontal = list( - getattr(admin_cls, 'filter_horizontal', ())) + getattr(modeladmin, 'filter_horizontal', ())) modeladmin.filter_horizontal.append('related_pages') modeladmin.add_extension_options(_('Related pages'), { diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index fa1f640a7..28c41cfa8 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -8,6 +8,7 @@ from feincms import settings + # ------------------------------------------------------------------------ class PageSitemap(Sitemap): """ From 98f109a6a24195b7a5ecfb94f5387fef33ede684 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 12:07:14 +0100 Subject: [PATCH 0834/1590] FeinCMS v1.8.1 Terrible oversights. --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 96c63ae9f..49fafd6db 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 8, 0) +VERSION = (1, 8, 1) __version__ = '.'.join(map(str, VERSION)) From 1e342a2593b0d4b551f501c00dde3a703eaa02f4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 12 Nov 2013 12:13:47 +0100 Subject: [PATCH 0835/1590] Remove the deprecated _feincms_extensions attribute --- docs/deprecation.rst | 3 +++ docs/releases/1.9.rst | 4 ++++ feincms/extensions.py | 10 ---------- feincms/module/page/modeladmins.py | 2 -- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index e8cd6d6af..36dc07668 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -98,3 +98,6 @@ will be issued for at least two releases. * All extensions should inherit from ``feincms.extensions.Extension``. Support for ``register(cls, admin_cls)``-style functions will be removed in FeinCMS v1.9. + +* The ``_feincms_extensions`` attribute on the page model and on models + inheriting ``ExtensionsMixin`` is gone. diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index f28007ae0..19d42572a 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -25,6 +25,10 @@ Removal of deprecated features ``modeladmin.add_extension_options`` if you want extension fields to appear. +* The ``_feincms_extensions`` property on the page model (and on all models + inheriting ``ExtensionsMixin`` has been removed. It has been deprecated + since FeinCMS v1.7. + New deprecations ================ diff --git a/feincms/extensions.py b/feincms/extensions.py index 591d6106f..64597f2ca 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -2,7 +2,6 @@ Base types for extensions refactor """ -import warnings from functools import wraps from django.contrib import admin @@ -13,15 +12,6 @@ class ExtensionsMixin(object): - @property - def _feincms_extensions(self): - warnings.warn( - 'Start using _extensions instead of _feincms_extensions' - ' today!', - DeprecationWarning, stacklevel=2) - - return set(self._extensions) - @classmethod def register_extensions(cls, *extensions): """ diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 8e33a9f97..d27a963ce 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -4,8 +4,6 @@ from __future__ import absolute_import -import warnings - from django.conf import settings as django_settings from django.core.exceptions import PermissionDenied from django.contrib.contenttypes.models import ContentType From 23e063b67b3b8edb45cb967103dd9159ce79189f Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Wed, 13 Nov 2013 14:09:51 +1100 Subject: [PATCH 0836/1590] Make {% feincms_breadcrumbs %} isinstance check BasePage not Page. See #487 --- feincms/module/page/templatetags/feincms_page_tags.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 3b1f70365..7c336a5d8 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -10,7 +10,7 @@ from django.conf import settings from django.http import HttpRequest -from feincms.module.page.models import Page +from feincms.module.page.models import BasePage, Page from feincms.utils.templatetags import (SimpleNodeWithVarAndArgs, do_simple_node_with_var_and_args_helper, SimpleAssignmentNodeWithVarAndArgs, @@ -306,7 +306,7 @@ def feincms_breadcrumbs(page, include_self=True): {% feincms_breadcrumbs feincms_page %} """ - if not page or not isinstance(page, Page): + if not page or not isinstance(page, BasePage): raise ValueError("feincms_breadcrumbs must be called with a valid Page object") ancs = page.get_ancestors() From 2048ca3bafd3c167fb00ec5f41d9f7715f954955 Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Wed, 13 Nov 2013 14:11:59 +1100 Subject: [PATCH 0837/1590] Make {% feincms_breadcrumbs %} isinstance check BasePage not Page. See #487 --- feincms/module/page/templatetags/feincms_page_tags.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 3b1f70365..7c336a5d8 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -10,7 +10,7 @@ from django.conf import settings from django.http import HttpRequest -from feincms.module.page.models import Page +from feincms.module.page.models import BasePage, Page from feincms.utils.templatetags import (SimpleNodeWithVarAndArgs, do_simple_node_with_var_and_args_helper, SimpleAssignmentNodeWithVarAndArgs, @@ -306,7 +306,7 @@ def feincms_breadcrumbs(page, include_self=True): {% feincms_breadcrumbs feincms_page %} """ - if not page or not isinstance(page, Page): + if not page or not isinstance(page, BasePage): raise ValueError("feincms_breadcrumbs must be called with a valid Page object") ancs = page.get_ancestors() From 194401fc22bd8d8eb344b3a8c2fee93b3f30be4f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 13 Nov 2013 11:09:21 +0100 Subject: [PATCH 0838/1590] TranslatedObjectMixin should be treated with @python_2_unicode_compatible --- feincms/translations.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feincms/translations.py b/feincms/translations.py index a64e8714b..43e4d629d 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -35,6 +35,7 @@ class NewsTranslation(Translation(News)): from django.db import models from django.db.models import Q from django.utils import translation +from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from feincms.utils import queryset_transform @@ -157,6 +158,7 @@ def only_language(self, language=short_language_code): return self.filter(translations__language_code=language) +@python_2_unicode_compatible class TranslatedObjectMixin(object): """ Mixin with helper methods. From 80d55b13cd82206d71e500895e6b4f3a4b04e46d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 13 Nov 2013 11:11:39 +0100 Subject: [PATCH 0839/1590] FeinCMS v1.8.2 The don't break old code release. --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 49fafd6db..8f3f52664 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 8, 1) +VERSION = (1, 8, 2) __version__ = '.'.join(map(str, VERSION)) From f099d14671922a6c120fbb98be2c25cd248b70c0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 15 Nov 2013 10:15:29 +0100 Subject: [PATCH 0840/1590] Do not only include the page admin templates in the archive, also install them --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index a6cf436f5..80b25dc39 100755 --- a/setup.py +++ b/setup.py @@ -31,6 +31,7 @@ def read(filename): 'templates/*/*.*', 'templates/*/*/*.*', 'templates/*/*/*/*.*', + 'templates/*/*/*/*/*.*', ], }, install_requires=[ From 651c811ebfa8cee4b07c6942db2c6d40bb84ffb2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 15 Nov 2013 10:15:54 +0100 Subject: [PATCH 0841/1590] FeinCMS v1.8.3 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 8f3f52664..94f613519 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 8, 2) +VERSION = (1, 8, 3) __version__ = '.'.join(map(str, VERSION)) From 16b417f871c28bbb5dec9dab62cc8714d25f7c82 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 15 Nov 2013 12:55:15 +0100 Subject: [PATCH 0842/1590] Add Python version trove classifiers --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 80b25dc39..ebe0bba0a 100755 --- a/setup.py +++ b/setup.py @@ -48,6 +48,9 @@ def read(filename): 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.3', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Application Frameworks', From 7fc44ffe33994ecc799f6f11972da0700a0c601d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 15 Nov 2013 13:02:33 +0100 Subject: [PATCH 0843/1590] Build universal wheels --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index 6e39e3fe9..84a5a4d58 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,6 @@ [flake8] exclude= ignore=E501,E123,E124,E126,E128 + +[wheel] +universal = 1 From fbfb58abb7ed62fb562d198dc1ebdba4330f87b0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 17 Nov 2013 11:16:17 +0100 Subject: [PATCH 0844/1590] Fix #490: Item editor buttons for media files fixed for Django 1.6 --- .../admin/feincms/_content_type_buttons.html | 8 +++++--- feincms/templatetags/feincms_admin_tags.py | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/feincms/templates/admin/feincms/_content_type_buttons.html b/feincms/templates/admin/feincms/_content_type_buttons.html index 84b3b84ac..3f55699fd 100644 --- a/feincms/templates/admin/feincms/_content_type_buttons.html +++ b/feincms/templates/admin/feincms/_content_type_buttons.html @@ -1,4 +1,5 @@ {% load url from future %} +{% load feincms_admin_tags %} <script type="text/javascript"> /* type: content type identifier (required) @@ -8,6 +9,7 @@ keep: keep entry in content type dropdown (defaults to false) */ {% url "admin:medialibrary_mediafile_changelist" as media_library_url %} +{% is_popup_var as popup_var %} var CONTENT_TYPE_BUTTONS = [ { type: 'richtextcontent', @@ -28,7 +30,7 @@ type: 'mediafilecontent', keep: true, cssclass: 'imagecontent', - raw_id_picker: '{{ media_library_url }}?type__exact=image&pop=1' + raw_id_picker: '{{ media_library_url }}?type__exact=image&{{ popup_var }}' }, { type: 'gallerycontent', keep: true @@ -36,7 +38,7 @@ type: 'mediafilecontent', keep: true, cssclass: 'pdfcontent', - raw_id_picker: '{{ media_library_url }}?type__exact=pdf&pop=1' + raw_id_picker: '{{ media_library_url }}?type__exact=pdf&{{ popup_var }}' {% endif %} }, { type: 'oembedcontent', @@ -46,7 +48,7 @@ type: 'mediafilecontent', keep: true, cssclass: 'audiocontent', - raw_id_picker: '{{ media_library_url }}?type__exact=audio&pop=1' + raw_id_picker: '{{ media_library_url }}?type__exact=audio&{{ popup_var }}' {% endif %} } ]; diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py index 4a0b24664..2ada605d3 100644 --- a/feincms/templatetags/feincms_admin_tags.py +++ b/feincms/templatetags/feincms_admin_tags.py @@ -1,3 +1,4 @@ +import django from django import template @@ -43,3 +44,19 @@ def _filter_recursive(fields): fieldset.fields = new_fields return fieldset + + +@register.assignment_tag +def is_popup_var(): + """ + Django 1.6 requires _popup=1 for raw id field popups, earlier versions + require pop=1. + + The explicit version check is a bit ugly, but works well. + + (Wrong parameters aren't simply ignored by django.contrib.admin, the + change list actively errors out by redirecting to ?e=1) + """ + if django.VERSION < (1, 6): + return 'pop=1' + return '_popup=1' From 12adfd2b5469d577c56c3794ca64a57b91e8e98d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 17 Nov 2013 11:29:20 +0100 Subject: [PATCH 0845/1590] flake8-clean the code a bit We still have a few ignored error codes and excluded folders left. --- .gitignore | 2 +- docs/conf.py | 9 +++++---- example/blog_urls.py | 2 +- example/example.db | Bin 96256 -> 99328 bytes example/manage.py | 3 ++- example/models.py | 2 ++ example/urls.py | 2 +- setup.cfg | 2 +- tests/manage.py | 3 ++- tests/testapp/__init__.py | 1 - tests/testapp/applicationcontent_urls.py | 2 +- tests/testapp/blog_urls.py | 2 +- tests/testapp/models.py | 2 ++ tests/testapp/settings.py | 3 ++- tests/testapp/tests/__init__.py | 2 ++ tests/testapp/tests/test_cms.py | 8 +++++--- tests/testapp/tests/test_extensions.py | 5 ++--- tests/testapp/tests/test_page.py | 22 ++++++++++------------ tests/testapp/tests/test_stuff.py | 2 ++ tests/testapp/urls.py | 2 +- 20 files changed, 43 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index bdf8a629b..45f25c901 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,5 @@ tests/test.zip /docs/_build /tests/.tox /tests/.coverage -/tests/venv /tests/htmlcov +venv diff --git a/docs/conf.py b/docs/conf.py index c85f09ef1..bdb164441 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,7 +11,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -177,9 +178,9 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'FeinCMS.tex', u'FeinCMS Documentation', - u'Feinheit GmbH and contributors', 'manual'), +latex_documents = [( + 'index', 'FeinCMS.tex', u'FeinCMS Documentation', + u'Feinheit GmbH and contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/example/blog_urls.py b/example/blog_urls.py index a199caaf4..70932bbd2 100644 --- a/example/blog_urls.py +++ b/example/blog_urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import patterns, url from django.views import generic from feincms.module.blog.models import Entry diff --git a/example/example.db b/example/example.db index b4f1b46a486c43a9b2d7f4e831fba4117e864dbd..5c560d7d481a0043f5cdaba2da1bf3422c72748a 100644 GIT binary patch delta 1616 zcma)6TW=dh6yDjflQgN5R88cn71An7D1z9T*^8ZZa72g`CsB7D2Vb)0QZ`=4UVGP< zO`OZ3Ds>}Oh^JP5;H|1E#6u;bf>9~_0N&{f2;LA6AQg#9Q7gy;%(^LR8!mkrojv=_ zneY3~nYs9z`{Mf@S59}(eH2BhSD8sC^8GmSsdnR}D@DOn>%{SMu%~ercqp&OGuAlU ze9wDkr@B(oR@w7w1(g*7!<a<~4a=#ZR8bS+W<9<=ye$YD3brCuu2$8|#TZHo+po;5 z2iV}^#zw8CYmtq$t#}YENo!#M0E;l^!`O#|4B|tW4<YQwyoh<0loov`;KKn1aUnJk zVv#@CI`Fzr^|}dV01wDYy$cUoz35lyCGmN8H@r%@;SdF*@CRtX+i<AW&-cTTVJHDp z#f7{zj%?AYnd7#V-&)HXI$s*kZ{{}xb=1?02IUdk=CQ5YTee!!cs3vg)WEo)qr!L% zmDGwJ>~=~u`#7fceemV3eiyvwuu$Ovd;ssmd#!=jzJm_EcS5cE(<fho6ZExar%~&m zZ_*#p*NCSK-Mm$HdnVkFs1LPQv30AQ0FR*6n9Bh+Q`I4wzIlkZ4)Hy0`~bmQi3?pc zyi37f;9Uax8u|z6P6~iQa0U>idYRU8t7_d?9|TXO!D0HdeOFfpfOjZ(hiu=2bF%~& z^-g)9nbUOD&{r(g+8%SdGlub4wxZ?y#cEzR)qL*hmLVJxct0xy#Q=8azx*7y`U$gr z3jP82N$H=VBiBo}g@SJ4%;TRVe3JlvY6ChC0k=;9*ITE1s67gP1=k@<|4DyBXJ`g| z3oe5swbwjx{K`&aIMhu|0nmp*Lp{nS;K!nX1RnI@xr&*q63R@a%)Ftm=NL>+X<ANW z+A5h<-N-RRlB0N*gwvJsdak_wYPA%`qfAw`$VYgQY(LB#R#ToRH#y2!xx8K}haJ;L znTn<5EWMl$<H;fan0TyB^9A5J%93~%M4X7g0DkN)_~LRM*mS>#SOY<k0!2CtJE<BG ztu|}upm~gY*vzsYHx2x-*8_Jc8eFI755RS}ON<-^J8%~)N{!^y{|&Khm#~zG<5*%! zATb|H&lV(m2Fd9-me`CgrIWT|#|5ca;$o4~rd%Y99!Qt!?aGaOk6XI*_SBIJwe!r4 zk`pOIVHXS~y-<+JQBpBUj!l*1Xp)Pi<F*u0xL9<ClOjnjlgRQ)@pV&4RD<(|SkRW2 zD$88T&MYsiD&}laWmEOc^n766T&gK)p}ev!6jxXQWlcjrXU<|Rny)YY4V;teiL_YC zq_?J(v}|S4LTO&#)R$QYSXkATWg}~dRi~h|jKYt)!}<_@;t>+C!1KiR-*<@k3k~;C zz0b&vMHQPcFyx4WmEz2{!p;*((xz<AwB^dt`K?$aWy)-(L>v|*d#U8eU5$tTnE}u9 ynDbCw&SR%gP$5l@!516D6aPB>YzUF*$AZXy_{|3J7N2j}+5Z^!=b3eu%=%whg~bH` delta 392 zcmXX>y-OoO9G&0(CLbr8_z^Iog+U^SkaK2dGP~n}99YCgW33`=R>wnv_}K`8Ho?-c z#r2mW)xjNmUckS??%*s03p>$(*eK}AUH5qJ@ji}ElgAH<v*9GX5JFa)g_(C$x*7es z_AN(u2<}Av_6GKx*kF@<CNs4c`uUN?y)Qm5awDZF3eQNFDXDxdeNU{{gwK7ggFvrK zEnOKnQUs1t0N^mrOH7uSDsVZ?oN3{FRLT>aN4NRmp=>6eKuKJhvI5wQvg{7?TxeJK zV3Sa+5Uk)8*6}ws<5gu0EAGO05EyNoH7&Sdo>9gr*O;m?&#mb|8!3`SoQJSi6r#WG zWIBu3ja$enKI0R1I|HBL8l&!PZUQ~)N0_R=|Mje|m!BXJoo`j)AH7`-m$t|LOH)9j zU%QJ(E!sz0^fBF{bLlpvU`NzW(Zq5bzZ_fdF?`J>+H?q320uW9;05lZW4&76ttG1f Pf1nYY>d<K%z@ha9E@);F diff --git a/example/manage.py b/example/manage.py index 2a3cb9b1d..c778f2aac 100755 --- a/example/manage.py +++ b/example/manage.py @@ -1,5 +1,6 @@ #!/usr/bin/env python -import os, sys +import os +import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) diff --git a/example/models.py b/example/models.py index 51beb40e5..719a89db8 100644 --- a/example/models.py +++ b/example/models.py @@ -33,6 +33,7 @@ ('default', 'Default position'), )) + def get_admin_fields(form, *args, **kwargs): return { 'exclusive_subpages': forms.BooleanField( @@ -43,6 +44,7 @@ def get_admin_fields(form, *args, **kwargs): ), } + Page.create_content_type(ApplicationContent, APPLICATIONS=( ('blog_urls', 'Blog', { 'admin_fields': get_admin_fields, diff --git a/example/urls.py b/example/urls.py index a8fa04e1a..1347b39b8 100644 --- a/example/urls.py +++ b/example/urls.py @@ -7,7 +7,7 @@ admin.autodiscover() urlpatterns = patterns('', - url(r'^admin/', include(admin.site.urls) ), + url(r'^admin/', include(admin.site.urls)), url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': os.path.join(os.path.dirname(__file__), 'media/')}), url(r'', include('feincms.contrib.preview.urls')), diff --git a/setup.cfg b/setup.cfg index 84a5a4d58..53335f9d1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [flake8] -exclude= +exclude=venv,.tox ignore=E501,E123,E124,E126,E128 [wheel] diff --git a/tests/manage.py b/tests/manage.py index 6d057f444..e20cc5e6d 100755 --- a/tests/manage.py +++ b/tests/manage.py @@ -1,5 +1,6 @@ #!/usr/bin/env python -import os, sys +import os +import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings") diff --git a/tests/testapp/__init__.py b/tests/testapp/__init__.py index 8b1378917..e69de29bb 100644 --- a/tests/testapp/__init__.py +++ b/tests/testapp/__init__.py @@ -1 +0,0 @@ - diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index 7ef8227a6..00757b3bc 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -3,7 +3,7 @@ """ from django import template -from django.conf.urls import patterns, include, url +from django.conf.urls import patterns, url from django.http import HttpResponse, HttpResponseRedirect from feincms.views.decorators import standalone diff --git a/tests/testapp/blog_urls.py b/tests/testapp/blog_urls.py index a199caaf4..70932bbd2 100644 --- a/tests/testapp/blog_urls.py +++ b/tests/testapp/blog_urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import patterns, url from django.views import generic from feincms.module.blog.models import Entry diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 96bb1ff99..1f6225dd1 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -33,6 +33,7 @@ ('default', 'Default position'), )) + def get_admin_fields(form, *args, **kwargs): return { 'exclusive_subpages': forms.BooleanField( @@ -43,6 +44,7 @@ def get_admin_fields(form, *args, **kwargs): ), } + Page.create_content_type(ApplicationContent, APPLICATIONS=( ('testapp.blog_urls', 'Blog', {'admin_fields': get_admin_fields}), ('whatever', 'Test Urls', {'urls': 'testapp.applicationcontent_urls'}), diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index d4e455077..57ba1fb02 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -40,7 +40,8 @@ 'django.core.context_processors.i18n', 'django.core.context_processors.media', 'django.core.context_processors.static', - 'django.core.context_processors.request', # request context processor is needed + # request context processor is needed + 'django.core.context_processors.request', ) MIDDLEWARE_CLASSES = ( diff --git a/tests/testapp/tests/__init__.py b/tests/testapp/tests/__init__.py index 734127365..751eb9d7d 100644 --- a/tests/testapp/tests/__init__.py +++ b/tests/testapp/tests/__init__.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +# flake8: noqa + from __future__ import absolute_import from .test_cms import * diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index c27ab1fc0..17685740a 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -12,13 +12,13 @@ from feincms.content.contactform.models import ContactFormContent from feincms.content.file.models import FileContent -from feincms.content.image.models import ImageContent from feincms.content.raw.models import RawContent from feincms.content.richtext.models import RichTextContent from feincms.content.video.models import VideoContent from .test_stuff import ExampleCMSBase, Empty, ExampleCMSBase2 + # ------------------------------------------------------------------------ class SubRawContent(RawContent): title = models.CharField('title', max_length=100, blank=True) @@ -55,6 +55,7 @@ def test_02_rsscontent_creation(self): # Monkey-patch feedparser.parse to work with a local RSS dump so that # the tests run faster. _orig_parse = feedparser.parse + def _new_parse(link): return _orig_parse(open( os.path.join(os.path.dirname(__file__), 'yahoo.rss'), 'rb')) @@ -154,9 +155,11 @@ class Attachment(models.Model): class AnyContent(models.Model): attachment = models.ForeignKey(Attachment, related_name='anycontents') + class Meta: abstract = True - ct = ExampleCMSBase.create_content_type(AnyContent) + + ExampleCMSBase.create_content_type(AnyContent) self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) self.assertTrue(hasattr(Attachment, 'anycontents')) @@ -172,4 +175,3 @@ def test_10_content_type_subclasses(self): ct = ExampleCMSBase.content_type_for(RawContent) ct2 = ExampleCMSBase.content_type_for(SubRawContent) self.assertNotEqual(ct, ct2) - diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index ddb2a8157..1ca997416 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -1,10 +1,10 @@ # coding: utf-8 + from __future__ import absolute_import +from django.contrib.sites.models import Site from django.template.defaultfilters import slugify -from django.test.utils import override_settings from django.test import TestCase -from django.contrib.sites.models import Site from feincms.module.page.models import Page @@ -32,7 +32,6 @@ def setUp(self): self.page_de = de.parent self.page_en = en.parent - def create_page(self, title='Test page', parent=None, **kwargs): defaults = { 'template_key': 'base', diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 15d838ce3..62eaf6ec0 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -13,7 +13,6 @@ from django.contrib.auth.models import User, AnonymousUser from django.contrib.contenttypes.models import ContentType from django.core import mail -from django.core.urlresolvers import reverse from django.db import models from django.contrib.sites.models import Site from django.http import Http404, HttpResponseBadRequest @@ -42,8 +41,8 @@ from .test_stuff import Empty -# ------------------------------------------------------------------------ +# ------------------------------------------------------------------------ class PagesTestCase(TestCase): def setUp(self): u = User(username='test', is_active=True, is_staff=True, is_superuser=True) @@ -769,28 +768,28 @@ def test_17_feincms_nav(self): self.login() - self.create_page_through_admin('Page 1') # 1 + self.create_page_through_admin('Page 1') # 1 self.create_page_through_admin('Page 1.1', 1) - self.create_page_through_admin('Page 1.2', 1) # 3 + self.create_page_through_admin('Page 1.2', 1) # 3 self.create_page_through_admin('Page 1.2.1', 3) self.create_page_through_admin('Page 1.2.2', 3) self.create_page_through_admin('Page 1.2.3', 3) self.create_page_through_admin('Page 1.3', 1) - self.create_page_through_admin('Page 2') # 8 + self.create_page_through_admin('Page 2') # 8 self.create_page_through_admin('Page 2.1', 8) self.create_page_through_admin('Page 2.2', 8) self.create_page_through_admin('Page 2.3', 8) - self.create_page_through_admin('Page 3') # 12 + self.create_page_through_admin('Page 3') # 12 self.create_page_through_admin('Page 3.1', 12) self.create_page_through_admin('Page 3.2', 12) - self.create_page_through_admin('Page 3.3', 12) # 15 - self.create_page_through_admin('Page 3.3.1', 15) # 16 + self.create_page_through_admin('Page 3.3', 12) # 15 + self.create_page_through_admin('Page 3.3.1', 15) # 16 self.create_page_through_admin('Page 3.3.1.1', 16) self.create_page_through_admin('Page 3.3.2', 15) - self.create_page_through_admin('Page 4') # 19 + self.create_page_through_admin('Page 4') # 19 self.create_page_through_admin('Page 4.1', 19) self.create_page_through_admin('Page 4.2', 19) @@ -1148,7 +1147,8 @@ def test_25_applicationcontent(self): response = self.client.get(page.get_absolute_url() + 'response/') self.assertContains(response, 'Anything') - self.assertContains(response, '<h2>Main content</h2>') # Ensure response has been wrapped + # Ensure response has been wrapped + self.assertContains(response, '<h2>Main content</h2>') # Test standalone behavior self.assertEqual( @@ -1222,8 +1222,6 @@ def test_28_applicationcontent_reverse(self): region='main', ordering=0, urlconf_path='testapp.applicationcontent_urls') - from feincms.content.application.models import app_reverse, reverse - # test app_reverse self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), page.get_absolute_url()) diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 6cbebf050..9b429d233 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -19,6 +19,7 @@ from feincms.module.page.models import Page from feincms.utils import collect_dict_values, get_object, shorten_string + # ------------------------------------------------------------------------ class Empty(object): """ @@ -27,6 +28,7 @@ class Empty(object): pass + class DocTest(TestCase): def test_translation_short_language_code(self): doctest.testmod(feincms.translations) diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index 2e9d27ee5..b8d9511b1 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -7,7 +7,7 @@ from feincms.module.page.sitemap import PageSitemap -sitemaps = {'pages' : PageSitemap} +sitemaps = {'pages': PageSitemap} admin.autodiscover() From a1bb6d3f52dfe56f0d003972384c8f8e7bdddffc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 17 Nov 2013 11:54:03 +0100 Subject: [PATCH 0846/1590] Fix occurrences of E126 --- feincms/admin/item_editor.py | 4 +-- feincms/admin/tree_editor.py | 6 ++-- feincms/content/comments/models.py | 3 +- feincms/module/medialibrary/modeladmins.py | 4 +-- feincms/module/medialibrary/models.py | 26 +++++++------- feincms/module/page/modeladmins.py | 4 +-- feincms/translations.py | 8 ++--- feincms/utils/__init__.py | 4 +-- setup.cfg | 2 +- tests/testapp/tests/test_page.py | 40 +++++++++++----------- 10 files changed, 51 insertions(+), 50 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 09d251e14..a3f105dba 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -194,8 +194,8 @@ def get_extra_context(self, request): extra_context = { 'model': self.model, - 'available_templates': - getattr(self.model, '_feincms_templates', ()), + 'available_templates': getattr( + self.model, '_feincms_templates', ()), 'has_parent_attribute': hasattr(self.model, 'parent'), 'content_types': self.get_content_type_map(request), 'FEINCMS_JQUERY_NO_CONFLICT': settings.FEINCMS_JQUERY_NO_CONFLICT, diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index e717bed92..c75ae35d6 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -269,9 +269,9 @@ def indented_short_title(self, item): r += ( '<span id="page_marker-%d" class="page_marker%s"' ' style="width: %dpx;"> </span> ') % ( - item.pk, - changeable_class, - 14 + getattr(item, mptt_opts.level_attr) * 18) + item.pk, + changeable_class, + 14 + getattr(item, mptt_opts.level_attr) * 18) # r += '<span tabindex="0">' if hasattr(item, 'short_title') and callable(item.short_title): diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index e8f049234..a6b4d67a5 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -87,7 +87,8 @@ def process(self, request, **kwargs): 'content/comments/%s.html' % parent_type, 'content/comments/default-site.html', 'content/comments/default.html', - ], RequestContext(request, { + ], + RequestContext(request, { 'content': self, 'feincms_page': self.parent, 'parent': comment_page, diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index c5f9396a5..45112316f 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -137,8 +137,8 @@ def admin_thumbnail(self, obj): <a href="%(url)s" target="_blank"> <img src="%(image)s" alt="" /> </a>""" % { - 'url': obj.file.url, - 'image': image}) + 'url': obj.file.url, + 'image': image}) return '' admin_thumbnail.short_description = _('Preview') admin_thumbnail.allow_tags = True diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index ddac544a6..b3a37f074 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -205,19 +205,19 @@ def delete_mediafile(self, name=None): # ------------------------------------------------------------------------ MediaFileBase.register_filetypes( - # Should we be using imghdr.what instead of extension guessing? - ('image', _('Image'), lambda f: re.compile(r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), - ('video', _('Video'), lambda f: re.compile(r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv|flv)$', re.IGNORECASE).search(f)), - ('audio', _('Audio'), lambda f: re.compile(r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), - ('pdf', _('PDF document'), lambda f: f.lower().endswith('.pdf')), - ('swf', _('Flash'), lambda f: f.lower().endswith('.swf')), - ('txt', _('Text'), lambda f: f.lower().endswith('.txt')), - ('rtf', _('Rich Text'), lambda f: f.lower().endswith('.rtf')), - ('zip', _('Zip archive'), lambda f: f.lower().endswith('.zip')), - ('doc', _('Microsoft Word'), lambda f: re.compile(r'\.docx?$', re.IGNORECASE).search(f)), - ('xls', _('Microsoft Excel'), lambda f: re.compile(r'\.xlsx?$', re.IGNORECASE).search(f)), - ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile(r'\.pptx?$', re.IGNORECASE).search(f)), - ('other', _('Binary'), lambda f: True), # Must be last + # Should we be using imghdr.what instead of extension guessing? + ('image', _('Image'), lambda f: re.compile(r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), + ('video', _('Video'), lambda f: re.compile(r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv|flv)$', re.IGNORECASE).search(f)), + ('audio', _('Audio'), lambda f: re.compile(r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), + ('pdf', _('PDF document'), lambda f: f.lower().endswith('.pdf')), + ('swf', _('Flash'), lambda f: f.lower().endswith('.swf')), + ('txt', _('Text'), lambda f: f.lower().endswith('.txt')), + ('rtf', _('Rich Text'), lambda f: f.lower().endswith('.rtf')), + ('zip', _('Zip archive'), lambda f: f.lower().endswith('.zip')), + ('doc', _('Microsoft Word'), lambda f: re.compile(r'\.docx?$', re.IGNORECASE).search(f)), + ('xls', _('Microsoft Excel'), lambda f: re.compile(r'\.xlsx?$', re.IGNORECASE).search(f)), + ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile(r'\.pptx?$', re.IGNORECASE).search(f)), + ('other', _('Binary'), lambda f: True), # Must be last ) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index ddbf3e17d..349bbd493 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -115,8 +115,8 @@ def _actions_column(self, page): addable = getattr(page, 'feincms_addable', True) preview_url = "../../r/%s/%s/" % ( - ContentType.objects.get_for_model(self.model).id, - page.id) + ContentType.objects.get_for_model(self.model).id, + page.id) actions = super(PageAdmin, self)._actions_column(page) if addable: diff --git a/feincms/translations.py b/feincms/translations.py index 43e4d629d..4bbfe3150 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -188,10 +188,10 @@ def get_translation_cache_key(self, language_code=None): language_code = translation.get_language() return (('FEINCMS:%d:XLATION:' % getattr(settings, 'SITE_ID', 0)) + '-'.join(['%s' % s for s in ( - self._meta.db_table, - self.id, - language_code, - )])) + self._meta.db_table, + self.id, + language_code, + )])) def get_translation(self, language_code=None): if not language_code: diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index a8be246ed..afc206952 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -99,8 +99,8 @@ def path_to_cache_key(path, max_length=200, prefix=""): cache_key = 'FEINCMS:%d:%s:%s' % ( getattr(django_settings, 'SITE_ID', 0), - prefix, - path, + prefix, + path, ) return cache_key diff --git a/setup.cfg b/setup.cfg index 53335f9d1..5b8d7b9c3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [flake8] exclude=venv,.tox -ignore=E501,E123,E124,E126,E128 +ignore=E501,E123,E124,E128 [wheel] universal = 1 diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 62eaf6ec0..e2eb36805 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -52,22 +52,22 @@ def setUp(self): self.site_1 = Site.objects.all()[0] Page.register_templates({ - 'key': 'base', - 'title': 'Standard template', - 'path': 'feincms_base.html', - 'regions': ( - ('main', 'Main content area'), - ('sidebar', 'Sidebar', 'inherited'), - ), - }, { - 'key': 'theother', - 'title': 'This actually exists', - 'path': 'base.html', - 'regions': ( - ('main', 'Main content area'), - ('sidebar', 'Sidebar', 'inherited'), - ), - }) + 'key': 'base', + 'title': 'Standard template', + 'path': 'feincms_base.html', + 'regions': ( + ('main', 'Main content area'), + ('sidebar', 'Sidebar', 'inherited'), + ), + }, { + 'key': 'theother', + 'title': 'This actually exists', + 'path': 'base.html', + 'regions': ( + ('main', 'Main content area'), + ('sidebar', 'Sidebar', 'inherited'), + ), + }) def login(self): self.assertTrue(self.client.login(username='test', password='test')) @@ -643,11 +643,11 @@ def test_15_b_client_frontend_editing(self): # manually register request processor # override_settings(FEINCMS_FRONTEND_EDITING=True) wont work here Page.register_request_processor( - processors.frontendediting_request_processor, - key='frontend_editing') + processors.frontendediting_request_processor, + key='frontend_editing') response = self.client.get(page.get_absolute_url() + - '?frontend_editing=1', - follow=True) + '?frontend_editing=1', + follow=True) self.assertRedirects(response, page.get_absolute_url()) self.assertIn('class="fe_box"', response.content.decode('utf-8')) self.assertIn('frontend_editing', self.client.cookies) From 68d155e25eb2c8d1f2facf1353efea9324d59a56 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 17 Nov 2013 13:57:37 +0100 Subject: [PATCH 0847/1590] FeinCMS v1.8.4 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 94f613519..ca8b56c79 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 8, 3) +VERSION = (1, 8, 4) __version__ = '.'.join(map(str, VERSION)) From 12f0934278b5c771a1f26b72b08183f6b37e0649 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 17 Nov 2013 13:59:51 +0100 Subject: [PATCH 0848/1590] Try again --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index ebe0bba0a..b7bef126f 100755 --- a/setup.py +++ b/setup.py @@ -48,8 +48,10 @@ def read(filename): 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', + 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development', From 6f8b9d5d796ced670043a992bb8e0e011b26f1d0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Nov 2013 12:09:19 +0100 Subject: [PATCH 0849/1590] Update jQuery and jQuery UI Refs #489. --- feincms/static/feincms/item_editor.js | 107 ++++---- feincms/static/feincms/jquery-1.8.3.min.js | 2 - feincms/static/feincms/jquery-1.9.1.min.js | 5 + .../feincms/jquery-ui-1.10.3.custom.min.js | 6 + .../feincms/jquery-ui-1.8.22.custom.min.js | 125 ---------- feincms/static/feincms/jquery.alerts.js | 235 ------------------ feincms/static/feincms/style.css | 66 ----- feincms/templates/admin/feincms/fe_tools.html | 6 +- .../admin/feincms/load-jquery.include | 7 +- 9 files changed, 65 insertions(+), 494 deletions(-) delete mode 100644 feincms/static/feincms/jquery-1.8.3.min.js create mode 100644 feincms/static/feincms/jquery-1.9.1.min.js create mode 100755 feincms/static/feincms/jquery-ui-1.10.3.custom.min.js delete mode 100755 feincms/static/feincms/jquery-ui-1.8.22.custom.min.js delete mode 100644 feincms/static/feincms/jquery.alerts.js diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 4a26c81c5..b9dc52874 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -374,46 +374,41 @@ if(!Array.indexOf) { update_item_controls(new_fieldset, ACTIVE_REGION); }); - $("h2 img.item-delete").live('click', function(){ - var popup_bg = '<div class="popup_bg"></div>'; - $("body").append(popup_bg); + $(document.body).on('click', 'h2 img.item-delete', function() { var item = $(this).parents(".order-item"); - jConfirm(DELETE_MESSAGES[0], DELETE_MESSAGES[1], function(r) { - if (r==true) { - var in_database = item.find(".delete-field").length; - if(in_database==0){ // remove on client-side only - var id = item.find(".item-content > div").attr('id'); - - // poorify all contents - items = item.parents('.order-machine').find('.order-item'); - items.each(function() { - poorify_rich($(this)); - }) - - // remove content - django.jQuery('#'+id).find('a.inline-deletelink') - .triggerHandler('click'); - - // richify all contents again - items.each(function() { - richify_poor($(this)); - }) - } - else{ // saved on server, don't remove form - set_item_field_value(item,"delete-field","checked"); - } - item.fadeOut(200, function() { - var region_item = $("#"+REGION_MAP[ACTIVE_REGION]+"_body"); - if (region_item.children("div.order-machine").children(":visible").length == 0) { - region_item.children("div.empty-machine-msg").show(); - } - }); + if (confirm(DELETE_MESSAGES[0])) { + var in_database = item.find(".delete-field").length; + if(in_database==0){ // remove on client-side only + var id = item.find(".item-content > div").attr('id'); + + // poorify all contents + items = item.parents('.order-machine').find('.order-item'); + items.each(function() { + poorify_rich($(this)); + }) + + // remove content + django.jQuery('#'+id).find('a.inline-deletelink') + .triggerHandler('click'); + + // richify all contents again + items.each(function() { + richify_poor($(this)); + }) } - $(".popup_bg").remove(); - }); + else{ // saved on server, don't remove form + set_item_field_value(item,"delete-field","checked"); + } + item.fadeOut(200, function() { + var region_item = $("#"+REGION_MAP[ACTIVE_REGION]+"_body"); + if (region_item.children("div.order-machine").children(":visible").length == 0) { + region_item.children("div.empty-machine-msg").show(); + } + }); + } }); - $('h2 span.collapse').live('click', function(){ + $(document.body).on('click', 'h2 span.collapse', function() { var node = this; $(this.parentNode.parentNode).children('.item-content').slideToggle(function(){ $(node).text(feincms_gettext($(this).is(':visible') ? 'Hide' : 'Show')); @@ -440,9 +435,6 @@ if(!Array.indexOf) { if(new_regions.indexOf(current_regions[i])==-1) not_in_new.push(current_regions[i]); - var popup_bg = '<div id="popup_bg"></div>'; - $("body").append(popup_bg); - var msg = CHANGE_TEMPLATE_MESSAGES[1]; if(not_in_new.length) { @@ -452,29 +444,26 @@ if(!Array.indexOf) { }, true); } - jConfirm(msg, CHANGE_TEMPLATE_MESSAGES[0], function(ret) { - if(ret) { - for(var i=0; i<not_in_new.length; i++) { - var body = $('#' + not_in_new[i] + '_body'), - machine = body.find('.order-machine'), - inputs = machine.find('input[name$=region]'); - - inputs.val(new_regions[0]); - } + if (confirm(msg)) { + for(var i=0; i<not_in_new.length; i++) { + var body = $('#' + not_in_new[i] + '_body'), + machine = body.find('.order-machine'), + inputs = machine.find('input[name$=region]'); - input_element.checked = true; + inputs.val(new_regions[0]); + } - form_element.append('<input type="hidden" name="_continue" value="1" />'); - /* Simulate a click on the save button instead of form.submit(), so - that the submit handlers from FilteredSelectMultiple get - invoked. See Issue #372 */ - form_element.find('input[type=submit][name=_save]').click(); + input_element.checked = true; - } else { - $("div#popup_bg").remove(); - form_element.val($(input_element).data('original_value')); // Restore original value - } - }); + form_element.append('<input type="hidden" name="_continue" value="1" />'); + /* Simulate a click on the save button instead of form.submit(), so + that the submit handlers from FilteredSelectMultiple get + invoked. See Issue #372 */ + form_element.find('input[type=submit][name=_save]').click(); + } else { + // Restore original value + form_element.val($(input_element).data('original_value')); + } return false; } diff --git a/feincms/static/feincms/jquery-1.8.3.min.js b/feincms/static/feincms/jquery-1.8.3.min.js deleted file mode 100644 index 83589daa7..000000000 --- a/feincms/static/feincms/jquery-1.8.3.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v1.8.3 jquery.com | jquery.org/license */ -(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-1.9.1.min.js b/feincms/static/feincms/jquery-1.9.1.min.js new file mode 100644 index 000000000..006e95310 --- /dev/null +++ b/feincms/static/feincms/jquery-1.9.1.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery.min.map +*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; +return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) +}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-ui-1.10.3.custom.min.js b/feincms/static/feincms/jquery-ui-1.10.3.custom.min.js new file mode 100755 index 000000000..7bda6aa93 --- /dev/null +++ b/feincms/static/feincms/jquery-ui-1.10.3.custom.min.js @@ -0,0 +1,6 @@ +/*! jQuery UI - v1.10.3 - 2013-11-17 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js +* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ + +(function(e,t){function i(t,i){var s,n,r,o=t.nodeName.toLowerCase();return"area"===o?(s=t.parentNode,n=s.name,t.href&&n&&"map"===s.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&a(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&a(t)}function a(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var s=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,a){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),a&&a.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var a,s,n=e(this[0]);n.length&&n[0]!==document;){if(a=n.css("position"),("absolute"===a||"relative"===a||"fixed"===a)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++s)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,a){return!!e.data(t,a[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var a=e.attr(t,"tabindex"),s=isNaN(a);return(s||a>=0)&&i(t,!s)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(i,a){function s(t,i,a,s){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,a&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===a?["Left","Right"]:["Top","Bottom"],r=a.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+a]=function(i){return i===t?o["inner"+a].call(this):this.each(function(){e(this).css(r,s(this,i)+"px")})},e.fn["outer"+a]=function(t,i){return"number"!=typeof t?o["outer"+a].call(this,t):this.each(function(){e(this).css(r,s(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,a){var s,n=e.ui[t].prototype;for(s in a)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([i,a[s]])},call:function(e,t,i){var a,s=e.plugins[t];if(s&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(a=0;s.length>a;a++)e.options[s[a][0]]&&s[a][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var a=i&&"left"===i?"scrollLeft":"scrollTop",s=!1;return t[a]>0?!0:(t[a]=1,s=t[a]>0,t[a]=0,s)}})})(jQuery);(function(e,t){var i=0,s=Array.prototype.slice,a=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(n){}a(t)},e.widget=function(i,s,a){var n,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],n=u+"-"+i,a||(a=s,s=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:a.version,_proto:e.extend({},a),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(a,function(i,a){return e.isFunction(a)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,n=this._superApply;return this._super=e,this._superApply=t,i=a.apply(this,arguments),this._super=s,this._superApply=n,i}}(),t):(l[i]=a,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:n}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var a,n,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(a in r[o])n=r[o][a],r[o].hasOwnProperty(a)&&n!==t&&(i[a]=e.isPlainObject(n)?e.isPlainObject(i[a])?e.widget.extend({},i[a],n):e.widget.extend({},n):n);return i},e.widget.bridge=function(i,a){var n=a.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,a=e.data(this,n);return a?e.isFunction(a[r])&&"_"!==r.charAt(0)?(s=a[r].apply(a,h),s!==a&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,n);t?t.option(r||{})._init():e.data(this,n,new a(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var a,n,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},a=i.split("."),i=a.shift(),a.length){for(n=o[i]=e.widget.extend({},this.options[i]),r=0;a.length-1>r;r++)n[a[r]]=n[a[r]]||{},n=n[a[r]];if(i=a.pop(),s===t)return n[i]===t?null:n[i];n[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,a){var n,r=this;"boolean"!=typeof i&&(a=s,s=i,i=!1),a?(s=n=e(s),this.bindings=this.bindings.add(s)):(a=s,s=this.element,n=this.widget()),e.each(a,function(a,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=a.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?n.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var a,n,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],n=i.originalEvent)for(a in n)a in i||(i[a]=n[a]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,a,n){"string"==typeof a&&(a={effect:a});var r,o=a?a===!0||"number"==typeof a?i:a.effect||i:t;a=a||{},"number"==typeof a&&(a={duration:a}),r=!e.isEmptyObject(a),a.complete=n,a.delay&&s.delay(a.delay),r&&e.effects&&e.effects.effect[o]?s[t](a):o!==t&&s[o]?s[o](a.duration,a.easing,n):s.queue(function(i){e(this)[t](),n&&n.call(s[0]),i()})}})})(jQuery);(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.3",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,a=1===i.which,n="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return a&&!n&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(e){function t(e,t,i){return e>t&&t+i>e}function i(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))}e.widget("ui.sortable",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===e.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_setOption:function(t,i){"disabled"===t?(this.options[t]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):e.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(t,i){var s=null,a=!1,n=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,n.widgetName+"-item")===n?(s=e(this),!1):undefined}),e.data(t.target,n.widgetName+"-item")===n&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(a=!0)}),a)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var a,n,r=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,r.cursorAt&&this._adjustOffsetFromHelper(r.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),r.containment&&this._setContainment(),r.cursor&&"auto"!==r.cursor&&(n=this.document.find("body"),this.storedCursor=n.css("cursor"),n.css("cursor",r.cursor),this.storedStylesheet=e("<style>*{ cursor: "+r.cursor+" !important; }</style>").appendTo(n)),r.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",r.opacity)),r.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",r.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(a=this.containers.length-1;a>=0;a--)this.containers[a]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!r.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,a,n,r=this.options,o=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY<r.scrollSensitivity?this.scrollParent[0].scrollTop=o=this.scrollParent[0].scrollTop+r.scrollSpeed:t.pageY-this.overflowOffset.top<r.scrollSensitivity&&(this.scrollParent[0].scrollTop=o=this.scrollParent[0].scrollTop-r.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-t.pageX<r.scrollSensitivity?this.scrollParent[0].scrollLeft=o=this.scrollParent[0].scrollLeft+r.scrollSpeed:t.pageX-this.overflowOffset.left<r.scrollSensitivity&&(this.scrollParent[0].scrollLeft=o=this.scrollParent[0].scrollLeft-r.scrollSpeed)):(t.pageY-e(document).scrollTop()<r.scrollSensitivity?o=e(document).scrollTop(e(document).scrollTop()-r.scrollSpeed):e(window).height()-(t.pageY-e(document).scrollTop())<r.scrollSensitivity&&(o=e(document).scrollTop(e(document).scrollTop()+r.scrollSpeed)),t.pageX-e(document).scrollLeft()<r.scrollSensitivity?o=e(document).scrollLeft(e(document).scrollLeft()-r.scrollSpeed):e(window).width()-(t.pageX-e(document).scrollLeft())<r.scrollSensitivity&&(o=e(document).scrollLeft(e(document).scrollLeft()+r.scrollSpeed))),o!==!1&&e.ui.ddmanager&&!r.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],a=s.item[0],n=this._intersectsWithPointer(s),n&&s.instance===this.currentContainer&&a!==this.currentItem[0]&&this.placeholder[1===n?"next":"prev"]()[0]!==a&&!e.contains(this.placeholder[0],a)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],a):!0)){if(this.direction=1===n?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,a=this.placeholder.offset(),n=this.options.axis,r={};n&&"x"!==n||(r.left=a.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),n&&"y"!==n||(r.top=a.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(r,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,a=s+this.helperProportions.height,n=e.left,r=n+e.width,o=e.top,h=o+e.height,l=this.offset.click.top,u=this.offset.click.left,c="x"===this.options.axis||s+l>o&&h>s+l,d="y"===this.options.axis||t+u>n&&r>t+u,p=c&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>n&&r>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>o&&h>a-this.helperProportions.height/2},_intersectsWithPointer:function(e){var i="x"===this.options.axis||t(this.positionAbs.top+this.offset.click.top,e.top,e.height),s="y"===this.options.axis||t(this.positionAbs.left+this.offset.click.left,e.left,e.width),a=i&&s,n=this._getDragVerticalDirection(),r=this._getDragHorizontalDirection();return a?this.floating?r&&"right"===r||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var i=t(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),s=t(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),a=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&s||"left"===n&&!s:a&&("down"===a&&i||"up"===a&&!i)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){var i,s,a,n,r=[],o=[],h=this._connectWith();if(h&&t)for(i=h.length-1;i>=0;i--)for(a=e(h[i]),s=a.length-1;s>=0;s--)n=e.data(a[s],this.widgetFullName),n&&n!==this&&!n.options.disabled&&o.push([e.isFunction(n.options.items)?n.options.items.call(n.element):e(n.options.items,n.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),n]);for(o.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=o.length-1;i>=0;i--)o[i][0].each(function(){r.push(this)});return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,a,n,r,o,h,l,u=this.items,c=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(a=e(d[i]),s=a.length-1;s>=0;s--)n=e.data(a[s],this.widgetFullName),n&&n!==this&&!n.options.disabled&&(c.push([e.isFunction(n.options.items)?n.options.items.call(n.element[0],t,{item:this.currentItem}):e(n.options.items,n.element),n]),this.containers.push(n));for(i=c.length-1;i>=0;i--)for(r=c[i][1],o=c[i][0],s=0,l=o.length;l>s;s++)h=e(o[s]),h.data(this.widgetName+"-item",r),u.push({item:h,instance:r,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,a,n;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(a=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=a.outerWidth(),s.height=a.outerHeight()),n=a.offset(),s.left=n.left,s.top=n.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)n=this.containers[i].element.offset(),this.containers[i].containerCache.left=n.left,this.containers[i].containerCache.top=n.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),a=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?t.currentItem.children().each(function(){e("<td> </td>",t.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(a)}):"img"===s&&a.attr("src",t.currentItem.attr("src")),i||a.css("visibility","hidden"),a},update:function(e,a){(!i||s.forcePlaceholderSize)&&(a.height()||a.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),a.width()||a.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_contactContainers:function(s){var a,n,r,o,h,l,u,c,d,p,f=null,m=null;for(a=this.containers.length-1;a>=0;a--)if(!e.contains(this.currentItem[0],this.containers[a].element[0]))if(this._intersectsWith(this.containers[a].containerCache)){if(f&&e.contains(this.containers[a].element[0],f.element[0]))continue;f=this.containers[a],m=a}else this.containers[a].containerCache.over&&(this.containers[a]._trigger("out",s,this._uiHash(this)),this.containers[a].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[m].containerCache.over||(this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1);else{for(r=1e4,o=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",u=this.positionAbs[h]+this.offset.click[h],n=this.items.length-1;n>=0;n--)e.contains(this.containers[m].element[0],this.items[n].item[0])&&this.items[n].item[0]!==this.currentItem[0]&&(!p||t(this.positionAbs.top+this.offset.click.top,this.items[n].top,this.items[n].height))&&(c=this.items[n].item.offset()[h],d=!1,Math.abs(c-u)>Math.abs(c+this.items[n][l]-u)&&(d=!0,c+=this.items[n][l]),r>Math.abs(c-u)&&(r=Math.abs(c-u),o=this.items[n],this.direction=d?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[m])return;o?this._rearrange(s,o,null,!0):this._rearrange(s,null,this.containers[m].element,!0),this._trigger("change",s,this._uiHash()),this.containers[m]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[m],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,a=this.options;"parent"===a.containment&&(a.containment=this.helper[0].parentNode),("document"===a.containment||"window"===a.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,e("document"===a.containment?document:window).width()-this.helperProportions.width-this.margins.left,(e("document"===a.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(a.containment)||(t=e(a.containment)[0],i=e(a.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,a="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,n=/(html|body)/i.test(a[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():n?0:a.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():n?0:a.scrollLeft())*s}},_generatePosition:function(t){var i,s,a=this.options,n=t.pageX,r=t.pageY,o="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(o[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.left<this.containment[0]&&(n=this.containment[0]+this.offset.click.left),t.pageY-this.offset.click.top<this.containment[1]&&(r=this.containment[1]+this.offset.click.top),t.pageX-this.offset.click.left>this.containment[2]&&(n=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(r=this.containment[3]+this.offset.click.top)),a.grid&&(i=this.originalPageY+Math.round((r-this.originalPageY)/a.grid[1])*a.grid[1],r=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-a.grid[1]:i+a.grid[1]:i,s=this.originalPageX+Math.round((n-this.originalPageX)/a.grid[0])*a.grid[0],n=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-a.grid[0]:s+a.grid[0]:s)),{top:r-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:o.scrollTop()),left:n-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:o.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var a=this.counter;this._delay(function(){a===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&s.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||s.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(s.push(function(e){this._trigger("remove",e,this._uiHash())}),s.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)t||s.push(function(e){return function(t){e._trigger("deactivate",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(e){return function(t){e._trigger("out",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!t){for(this._trigger("beforeStop",e,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!1}if(t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!t){for(i=0;s.length>i;i++)s[i].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}})})(jQuery); \ No newline at end of file diff --git a/feincms/static/feincms/jquery-ui-1.8.22.custom.min.js b/feincms/static/feincms/jquery-ui-1.8.22.custom.min.js deleted file mode 100755 index e36a7f0f6..000000000 --- a/feincms/static/feincms/jquery-ui-1.8.22.custom.min.js +++ /dev/null @@ -1,125 +0,0 @@ -/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.core.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.22",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.widget.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.mouse.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.position.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.draggable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){return d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.22"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g=b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensitivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.push({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{start:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!e.length)return;var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.droppable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);return this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable"),this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;return this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance))return e=!0,!1}),e?!1:this.accept.call(this.element[0],d.currentItem||d.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d)),this.element):!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.22"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.left,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h<d.length;h++){if(d[h].options.disabled||b&&!d[h].accept.call(d[h].element[0],b.currentItem||b.element))continue;for(var i=0;i<f.length;i++)if(f[i]==d[h].element[0]){d[h].proportions.height=0;continue g}d[h].visible=d[h].element.css("display")!="none";if(!d[h].visible)continue;e=="mousedown"&&d[h]._activate.call(d[h],c),d[h].offset=d[h].element.offset(),d[h].proportions={width:d[h].element[0].offsetWidth,height:d[h].element[0].offsetHeight}}},drop:function(b,c){var d=!1;return a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c))}),d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.resizable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;return d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width)),a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=this.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(!a.browser.msie||!a(c).is(":hidden")&&!a(c).parents(":hidden").length)e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0});else continue}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.22"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.selectable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}),!1},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;return a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove(),!1}}),a.extend(a.ui.selectable,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.sortable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=this.options.axis==="x"||a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=this.options.axis==="y"||a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();return e?this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1):!1},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f&&this.ready)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i],this.direction=j-h>0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._uiHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.accordion.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}return f?(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),!1):!0},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];return this._clickHandler({target:b},b),this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(d.disabled)return;if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!g)return;return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(this.running)return;this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data)}}),a.extend(a.ui.accordion,{version:"1.8.22",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size()){b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);return}if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.autocomplete.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.isMultiLine=this.element.is("textarea"),this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(b.options.disabled||b.element.propAttr("readOnly"))return;d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._keyEvent("previous",c);break;case e.DOWN:b._keyEvent("next",c);break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){if(b.options.disabled)return;b.selectedItem=null,b.previous=b.element.val()}).bind("blur.autocomplete",function(a){if(b.options.disabled)return;clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150)}),this._initSource(),this.menu=a("<ul></ul>").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,c,d;a.isArray(this.options.source)?(c=this.options.source,this.source=function(b,d){d(a.ui.autocomplete.filter(c,b.term))}):typeof this.options.source=="string"?(d=this.options.source,this.source=function(c,e){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:d,data:c,dataType:"json",success:function(a,b){e(a)},error:function(){e([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)===!1)return;return this._search(a)},_search:function(a){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.source({term:a},this._response())},_response:function(){var a=this,b=++c;return function(d){b===c&&a.__response(d),a.pending--,a.pending||a.element.removeClass("ui-autocomplete-loading")}},__response:function(a){!this.options.disabled&&a&&a.length?(a=this._normalize(a),this._suggest(a),this._trigger("open")):this.close()},close:function(a){clearTimeout(this.closing),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.deactivate(),this._trigger("close",a))},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(b){return b.length&&b[0].label&&b[0].value?b:a.map(b,function(b){return typeof b=="string"?{label:b,value:b}:a.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(b){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(c,b),this.menu.deactivate(),this.menu.refresh(),c.show(),this._resizeMenu(),c.position(a.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(new a.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(b,c){var d=this;a.each(c,function(a,c){d._renderItem(b,c)})},_renderItem:function(b,c){return a("<li></li>").data("item.autocomplete",c).append(a("<a></a>").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)},widget:function(){return this.menu.element},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})})(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(!a(c.target).closest(".ui-menu-item a").length)return;c.preventDefault(),b.select(c)}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){if(!this.active)return;this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active){this.activate(c,this.element.children(b));return}var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:first")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[a.fn.prop?"prop":"attr"]("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})}(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.button.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);return c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form})),e};a.widget("ui.button",{options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",j),typeof this.options.disabled!="boolean"?this.options.disabled=!!this.element.propAttr("disabled"):this.element.propAttr("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var b=this,h=this.options,i=this.type==="checkbox"||this.type==="radio",l="ui-state-hover"+(i?"":" ui-state-active"),m="ui-state-focus";h.label===null&&(h.label=this.buttonElement.html()),this.buttonElement.addClass(g).attr("role","button").bind("mouseenter.button",function(){if(h.disabled)return;a(this).addClass("ui-state-hover"),this===c&&a(this).addClass("ui-state-active")}).bind("mouseleave.button",function(){if(h.disabled)return;a(this).removeClass(l)}).bind("click.button",function(a){h.disabled&&(a.preventDefault(),a.stopImmediatePropagation())}),this.element.bind("focus.button",function(){b.buttonElement.addClass(m)}).bind("blur.button",function(){b.buttonElement.removeClass(m)}),i&&(this.element.bind("change.button",function(){if(f)return;b.refresh()}),this.buttonElement.bind("mousedown.button",function(a){if(h.disabled)return;f=!1,d=a.pageX,e=a.pageY}).bind("mouseup.button",function(a){if(h.disabled)return;if(d!==a.pageX||e!==a.pageY)f=!0})),this.type==="checkbox"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).toggleClass("ui-state-active"),b.buttonElement.attr("aria-pressed",b.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).addClass("ui-state-active"),b.buttonElement.attr("aria-pressed","true");var c=b.element[0];k(c).not(c).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown.button",function(){if(h.disabled)return!1;a(this).addClass("ui-state-active"),c=this,a(document).one("mouseup",function(){c=null})}).bind("mouseup.button",function(){if(h.disabled)return!1;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(b){if(h.disabled)return!1;(b.keyCode==a.ui.keyCode.SPACE||b.keyCode==a.ui.keyCode.ENTER)&&a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(b){b.keyCode===a.ui.keyCode.SPACE&&a(this).click()})),this._setOption("disabled",h.disabled),this._resetButton()},_determineButtonType:function(){this.element.is(":checkbox")?this.type="checkbox":this.element.is(":radio")?this.type="radio":this.element.is("input")?this.type="input":this.type="button";if(this.type==="checkbox"||this.type==="radio"){var a=this.element.parents().filter(":last"),b="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(b),this.buttonElement.length||(a=a.length?a.siblings():this.element.siblings(),this.buttonElement=a.filter(b),this.buttonElement.length||(this.buttonElement=a.find(b))),this.element.addClass("ui-helper-hidden-accessible");var c=this.element.is(":checked");c&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.attr("aria-pressed",c)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(g+" "+h+" "+i).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title"),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled"){c?this.element.propAttr("disabled",!0):this.element.propAttr("disabled",!1);return}this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b),this.type==="radio"?k(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input"){this.options.label&&this.element.val(this.options.label);return}var b=this.buttonElement.removeClass(i),c=a("<span></span>",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>"),d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>"),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.dialog.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},f=a.attrFn||{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0,click:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("<div></div>")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("<span></span>")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("<span></span>").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=a("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('<button type="button"></button>').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(g);a.each(d,function(a,b){if(a==="click")return;a in f?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||" "))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.22",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()<a.ui.dialog.overlay.maxZ)return!1})},1),a(document).bind("keydown.dialog-overlay",function(c){b.options.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}),a(window).bind("resize.dialog-overlay",a.ui.dialog.overlay.resize));var c=(this.oldInstances.pop()||a("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b<c?a(window).height()+"px":b+"px"):a(document).height()+"px"},width:function(){var b,c;return a.browser.msie?(b=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),c=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth),b<c?a(window).width()+"px":b+"px"):a(document).width()+"px"},resize:function(){var b=a([]);a.each(a.ui.dialog.overlay.instances,function(){b=b.add(this)}),b.css({width:0,height:0}).css({width:a.ui.dialog.overlay.width(),height:a.ui.dialog.overlay.height()})}}),a.extend(a.ui.dialog.overlay.prototype,{destroy:function(){a.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.slider.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.tabs.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1<this.anchors.length?1:-1)),c.disabled=a.map(a.grep(c.disabled,function(a,c){return a!=b}),function(a,c){return a>=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.22"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a<c.anchors.length?a:0)},a),b&&b.stopPropagation()}),f=c._unrotate||(c._unrotate=b?function(a){e()}:function(a){a.clientX&&c.rotate(null)});return a?(this.element.bind("tabsshow",e),this.anchors.bind(d.event+".tabs",f),e()):(clearTimeout(c.rotation),this.element.unbind("tabsshow",e),this.anchors.unbind(d.event+".tabs",f),delete this._rotate,delete this._unrotate),this}})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.datepicker.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={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:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);if(!c.length)return;c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);if($.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])||!d.length)return;d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover")})}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}$.extend($.ui,{datepicker:{version:"1.8.22"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){return extendRemove(this._defaults,a||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);if(c.hasClass(this.markerClassName))return;this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a)},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]),!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);if(c.hasClass(this.markerClassName))return;c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block")},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f),this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);return c&&!c.inline&&this._setDateFromField(c,b),c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(d){$.datepicker.log(d)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if($.datepicker._isDisabledDatepicker(a)||$.datepicker._lastInput==a)return;var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){return e|=$(this).css("position")=="fixed",!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a)),this._attachHandlers(a);var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+(c?0:$(document).scrollLeft()),i=document.documentElement.clientHeight+(c?0:$(document).scrollTop());return b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0),b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!b||a&&b!=$.data(a,PROP_NAME))return;if(this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=function(){$.datepicker._tidyDialog(b)};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,e):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,e),c||e(),this._datepickerShowing=!1;var f=this._get(b,"onClose");f&&f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!$.datepicker._curInst)return;var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);if(this._isDisabledDatepicker(d[0]))return;this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e)},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if($(d).hasClass(this._unselectableClass)||this._isDisabledDatepicker(e[0]))return;var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;return c&&s++,c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;return r+=f[0].length,parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase())return f=c[0],r+=d.length,!1});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;do{var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}while(!0)}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;return c&&m++,c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;return c&&e++,c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()==a.lastVal)return;var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;return b.setDate(b.getDate()+a),b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());return f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0)),this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){return a?(a.setHours(a.getHours()>12?a.getHours()+2:0),a):null},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_attachHandlers:function(a){var b=this._get(a,"stepMonths"),c="#"+a.id;a.dpDiv.find("[data-handler]").map(function(){var a={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,-b,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,+b,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(c)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(c,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),a[this.getAttribute("data-handler")])})},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click">'+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' data-handler="selectDay" data-event="click" data-month="'+Y.getMonth()+'" data-year="'+Y.getFullYear()+'"')+">"+(bb&&!G?" ":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="</div>",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;return e=d&&e>d?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.22",window["DP_jQuery_"+dpuuid]=$})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.progressbar.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.22"})})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.core.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -jQuery.effects||function(a,b){function c(b){var c;return b&&b.constructor==Array&&b.length==3?b:(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))?[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)]:(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))?[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))?[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)]:(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))?[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)]:(c=/rgba\(0, 0, 0, 0\)/.exec(b))?e.transparent:e[a.trim(b).toLowerCase()]}function d(b,d){var e;do{e=(a.curCSS||a.css)(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};return a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete,[b,c,d,e]}function l(b){return!b||typeof b=="number"||a.fx.speeds[b]?!0:typeof b=="string"&&!a.effects[b]?!0:!1}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){return a.isFunction(d)&&(e=d,d=null),this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class")||"";a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.22",save:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.data("ec.storage."+b[c],a[0].style[b[c]])},restore:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.css(b[c],a.data("ec.storage."+b[c]))},setMode:function(a,b){return b=="toggle"&&(b=a.is(":hidden")?"show":"hide"),b},getBaseline:function(a,b){var c,d;switch(a[0]){case"top":c=0;break;case"middle":c=.5;break;case"bottom":c=1;break;default:c=a[0]/b.height}switch(a[1]){case"left":d=0;break;case"center":d=.5;break;case"right":d=1;break;default:d=a[1]/b.width}return{x:d,y:c}},createWrapper:function(b){if(b.parent().is(".ui-effects-wrapper"))return b.parent();var c={width:b.outerWidth(!0),height:b.outerHeight(!0),"float":b.css("float")},d=a("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}}),a.easing.jswing=a.easing.swing,a.extend(a.easing,{def:"easeOutQuad",swing:function(b,c,d,e,f){return a.easing[a.easing.def](b,c,d,e,f)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b+c:d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b+c:-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b*b+c:d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return b==0?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){return b==0?c:b==e?c+d:(b/=e/2)<1?d/2*Math.pow(2,10*(b-1))+c:d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){return(b/=e/2)<1?-d/2*(Math.sqrt(1-b*b)-1)+c:d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(b==0)return c;if((b/=e)==1)return c+d;g||(g=e*.3);if(h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g))+c},easeOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(b==0)return c;if((b/=e)==1)return c+d;g||(g=e*.3);if(h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*b)*Math.sin((b*e-f)*2*Math.PI/g)+d+c},easeInOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(b==0)return c;if((b/=e/2)==2)return c+d;g||(g=e*.3*1.5);if(h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return b<1?-0.5*h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g)+c:h*Math.pow(2,-10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g)*.5+d+c},easeInBack:function(a,c,d,e,f,g){return g==b&&(g=1.70158),e*(c/=f)*c*((g+1)*c-g)+d},easeOutBack:function(a,c,d,e,f,g){return g==b&&(g=1.70158),e*((c=c/f-1)*c*((g+1)*c+g)+1)+d},easeInOutBack:function(a,c,d,e,f,g){return g==b&&(g=1.70158),(c/=f/2)<1?e/2*c*c*(((g*=1.525)+1)*c-g)+d:e/2*((c-=2)*c*(((g*=1.525)+1)*c+g)+2)+d},easeInBounce:function(b,c,d,e,f){return e-a.easing.easeOutBounce(b,f-c,0,e,f)+d},easeOutBounce:function(a,b,c,d,e){return(b/=e)<1/2.75?d*7.5625*b*b+c:b<2/2.75?d*(7.5625*(b-=1.5/2.75)*b+.75)+c:b<2.5/2.75?d*(7.5625*(b-=2.25/2.75)*b+.9375)+c:d*(7.5625*(b-=2.625/2.75)*b+.984375)+c},easeInOutBounce:function(b,c,d,e,f){return c<f/2?a.easing.easeInBounce(b,c*2,0,e,f)*.5+d:a.easing.easeOutBounce(b,c*2-f,0,e,f)*.5+e*.5+d}})}(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.blind.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.bounce.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight(!0)/3:c.outerWidth(!0)/3);e=="show"&&c.css("opacity",0).css(j,k=="pos"?-g:g),e=="hide"&&(g=g/(h*2)),e!="hide"&&h--;if(e=="show"){var l={opacity:1};l[j]=(k=="pos"?"+=":"-=")+g,c.animate(l,i/2,b.options.easing),g=g/2,h--}for(var m=0;m<h;m++){var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing),g=e=="hide"?g*2:g/2}if(e=="hide"){var l={opacity:0};l[j]=(k=="pos"?"-=":"+=")+g,c.animate(l,i/2,b.options.easing,function(){c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}else{var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.clip.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.clip=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","height","width"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=c[0].tagName=="IMG"?g:c,i={size:f=="vertical"?"height":"width",position:f=="vertical"?"top":"left"},j=f=="vertical"?h.height():h.width();e=="show"&&(h.css(i.size,0),h.css(i.position,j/2));var k={};k[i.size]=e=="show"?j:0,k[i.position]=e=="show"?0:j/2,h.animate(k,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.drop.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.drop=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","opacity"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0)/2:c.outerWidth(!0)/2);e=="show"&&c.css("opacity",0).css(g,h=="pos"?-i:i);var j={opacity:e=="show"?1:0};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.explode.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.explode=function(b){return this.queue(function(){var c=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3,d=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?a(this).is(":visible")?"hide":"show":b.options.mode;var e=a(this).show().css("visibility","hidden"),f=e.offset();f.top-=parseInt(e.css("marginTop"),10)||0,f.left-=parseInt(e.css("marginLeft"),10)||0;var g=e.outerWidth(!0),h=e.outerHeight(!0);for(var i=0;i<c;i++)for(var j=0;j<d;j++)e.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.fade.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.fold.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.highlight.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.pulsate.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i<e;i++)c.animate({opacity:h},f,b.options.easing),h=(h+1)%2;c.animate({opacity:h},f,b.options.easing,function(){h==0&&c.hide(),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}).dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.scale.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.puff=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide"),e=parseInt(b.options.percent,10)||150,f=e/100,g={height:c.height(),width:c.width()};a.extend(b.options,{fade:!0,mode:d,percent:d=="hide"?e:100,from:d=="hide"?g:{height:g.height*f,width:g.width*f}}),c.effect("scale",b.options,b.duration,b.callback),c.dequeue()})},a.effects.scale=function(b){return this.queue(function(){var c=a(this),d=a.extend(!0,{},b.options),e=a.effects.setMode(c,b.options.mode||"effect"),f=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:e=="hide"?0:100),g=b.options.direction||"both",h=b.options.origin;e!="effect"&&(d.origin=h||["middle","center"],d.restore=!0);var i={height:c.height(),width:c.width()};c.from=b.options.from||(e=="show"?{height:0,width:0}:i);var j={y:g!="horizontal"?f/100:1,x:g!="vertical"?f/100:1};c.to={height:i.height*j.y,width:i.width*j.x},b.options.fade&&(e=="show"&&(c.from.opacity=0,c.to.opacity=1),e=="hide"&&(c.from.opacity=1,c.to.opacity=0)),d.from=c.from,d.to=c.to,d.mode=e,c.effect("size",d,b.duration,b.callback),c.dequeue()})},a.effects.size=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","width","height","overflow","opacity"],e=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],g=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],i=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],j=a.effects.setMode(c,b.options.mode||"effect"),k=b.options.restore||!1,l=b.options.scale||"both",m=b.options.origin,n={height:c.height(),width:c.width()};c.from=b.options.from||n,c.to=b.options.to||n;if(m){var p=a.effects.getBaseline(m,n);c.from.top=(n.height-c.from.height)*p.y,c.from.left=(n.width-c.from.width)*p.x,c.to.top=(n.height-c.to.height)*p.y,c.to.left=(n.width-c.to.width)*p.x}var q={from:{y:c.from.height/n.height,x:c.from.width/n.width},to:{y:c.to.height/n.height,x:c.to.width/n.width}};if(l=="box"||l=="both")q.from.y!=q.to.y&&(d=d.concat(h),c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(d=d.concat(i),c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to));(l=="content"||l=="both")&&q.from.y!=q.to.y&&(d=d.concat(g),c.from=a.effects.setTransition(c,g,q.from.y,c.from),c.to=a.effects.setTransition(c,g,q.to.y,c.to)),a.effects.save(c,k?d:e),c.show(),a.effects.createWrapper(c),c.css("overflow","hidden").css(c.from);if(l=="content"||l=="both")h=h.concat(["marginTop","marginBottom"]).concat(g),i=i.concat(["marginLeft","marginRight"]),f=d.concat(h).concat(i),c.find("*[width]").each(function(){var c=a(this);k&&a.effects.save(c,f);var d={height:c.height(),width:c.width()};c.from={height:d.height*q.from.y,width:d.width*q.from.x},c.to={height:d.height*q.to.y,width:d.width*q.to.x},q.from.y!=q.to.y&&(c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to)),c.css(c.from),c.animate(c.to,b.duration,b.options.easing,function(){k&&a.effects.restore(c,f)})});c.animate(c.to,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){c.to.opacity===0&&c.css("opacity",c.from.opacity),j=="hide"&&c.hide(),a.effects.restore(c,k?d:e),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.shake.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.shake=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"left",g=b.options.distance||20,h=b.options.times||3,i=b.duration||b.options.duration||140;a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",l={},m={},n={};l[j]=(k=="pos"?"-=":"+=")+g,m[j]=(k=="pos"?"+=":"-=")+g*2,n[j]=(k=="pos"?"-=":"+=")+g*2,c.animate(l,i,b.options.easing);for(var p=1;p<h;p++)c.animate(m,i,b.options.easing).animate(n,i,b.options.easing);c.animate(m,i,b.options.easing).animate(l,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.slide.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.slide=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"show"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c).css({overflow:"hidden"});var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0):c.outerWidth(!0));e=="show"&&c.css(g,h=="pos"?isNaN(i)?"-"+i:-i:i);var j={};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.22 - 2012-07-24 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.transfer.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.transfer=function(b){return this.queue(function(){var c=a(this),d=a(b.options.to),e=d.offset(),f={top:e.top,left:e.left,height:d.innerHeight(),width:d.innerWidth()},g=c.offset(),h=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);; \ No newline at end of file diff --git a/feincms/static/feincms/jquery.alerts.js b/feincms/static/feincms/jquery.alerts.js deleted file mode 100644 index a6ec14ed3..000000000 --- a/feincms/static/feincms/jquery.alerts.js +++ /dev/null @@ -1,235 +0,0 @@ -// jQuery Alert Dialogs Plugin -// -// Version 1.1 -// -// Cory S.N. LaViska -// A Beautiful Site (http://abeautifulsite.net/) -// 14 May 2009 -// -// Visit http://abeautifulsite.net/notebook/87 for more information -// -// Usage: -// jAlert( message, [title, callback] ) -// jConfirm( message, [title, callback] ) -// jPrompt( message, [value, title, callback] ) -// -// History: -// -// 1.00 - Released (29 December 2008) -// -// 1.01 - Fixed bug where unbinding would destroy all resize events -// -// License: -// -// This plugin is dual-licensed under the GNU General Public License and the MIT License and -// is copyright 2008 A Beautiful Site, LLC. -// -(function($) { - - $.alerts = { - - // These properties can be read/written by accessing $.alerts.propertyName from your scripts at any time - - verticalOffset: -75, // vertical offset of the dialog from center screen, in pixels - horizontalOffset: 0, // horizontal offset of the dialog from center screen, in pixels/ - repositionOnResize: true, // re-centers the dialog on window resize - overlayOpacity: .01, // transparency level of overlay - overlayColor: '#FFF', // base color of overlay - draggable: true, // make the dialogs draggable (requires UI Draggables plugin) - okButton: ' OK ', // text for the OK button - cancelButton: ' Cancel ', // text for the Cancel button - dialogClass: null, // if specified, this class will be applied to all dialogs - - // Public methods - - alert: function(message, title, callback) { - if( title == null ) title = 'Alert'; - $.alerts._show(title, message, null, 'alert', function(result) { - if( callback ) callback(result); - }); - }, - - confirm: function(message, title, callback) { - if( title == null ) title = 'Confirm'; - $.alerts._show(title, message, null, 'confirm', function(result) { - if( callback ) callback(result); - }); - }, - - prompt: function(message, value, title, callback) { - if( title == null ) title = 'Prompt'; - $.alerts._show(title, message, value, 'prompt', function(result) { - if( callback ) callback(result); - }); - }, - - // Private methods - - _show: function(title, msg, value, type, callback) { - - $.alerts._hide(); - $.alerts._overlay('show'); - - $("BODY").append( - '<div id="popup_container">' + - '<h1 id="popup_title"></h1>' + - '<div id="popup_content">' + - '<div id="popup_message"></div>' + - '</div>' + - '</div>'); - - if( $.alerts.dialogClass ) $("#popup_container").addClass($.alerts.dialogClass); - - // IE6 Fix - var pos = ($.browser.msie && parseInt($.browser.version) <= 6 ) ? 'absolute' : 'fixed'; - - $("#popup_container").css({ - position: pos, - zIndex: 99999, - padding: 0, - margin: 0 - }); - - $("#popup_title").text(title); - $("#popup_content").addClass(type); - $("#popup_message").text(msg); - $("#popup_message").html( $("#popup_message").text().replace(/\n/g, '<br />') ); - - $("#popup_container").css({ - minWidth: $("#popup_container").outerWidth(), - maxWidth: $("#popup_container").outerWidth() - }); - - $.alerts._reposition(); - $.alerts._maintainPosition(true); - - switch( type ) { - case 'alert': - $("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /></div>'); - $("#popup_ok").click( function() { - $.alerts._hide(); - callback(true); - }); - $("#popup_ok").focus().keypress( function(e) { - if( e.keyCode == 13 || e.keyCode == 27 ) $("#popup_ok").trigger('click'); - }); - break; - case 'confirm': - $("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>'); - $("#popup_ok").click( function() { - $.alerts._hide(); - if( callback ) callback(true); - }); - $("#popup_cancel").click( function() { - $.alerts._hide(); - if( callback ) callback(false); - }); - $("#popup_ok").focus(); - $("#popup_ok, #popup_cancel").keypress( function(e) { - if( e.keyCode == 13 ) $("#popup_ok").trigger('click'); - if( e.keyCode == 27 ) $("#popup_cancel").trigger('click'); - }); - break; - case 'prompt': - $("#popup_message").append('<br /><input type="text" size="30" id="popup_prompt" />').after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>'); - $("#popup_prompt").width( $("#popup_message").width() ); - $("#popup_ok").click( function() { - var val = $("#popup_prompt").val(); - $.alerts._hide(); - if( callback ) callback( val ); - }); - $("#popup_cancel").click( function() { - $.alerts._hide(); - if( callback ) callback( null ); - }); - $("#popup_prompt, #popup_ok, #popup_cancel").keypress( function(e) { - if( e.keyCode == 13 ) $("#popup_ok").trigger('click'); - if( e.keyCode == 27 ) $("#popup_cancel").trigger('click'); - }); - if( value ) $("#popup_prompt").val(value); - $("#popup_prompt").focus().select(); - break; - } - - // Make draggable - if( $.alerts.draggable ) { - try { - $("#popup_container").draggable({ handle: $("#popup_title") }); - $("#popup_title").css({ cursor: 'move' }); - } catch(e) { /* requires jQuery UI draggables */ } - } - }, - - _hide: function() { - $("#popup_container").remove(); - $.alerts._overlay('hide'); - $.alerts._maintainPosition(false); - }, - - _overlay: function(status) { - switch( status ) { - case 'show': - $.alerts._overlay('hide'); - $("BODY").append('<div id="popup_overlay"></div>'); - $("#popup_overlay").css({ - position: 'absolute', - zIndex: 99998, - top: '0px', - left: '0px', - width: '100%', - height: $(document).height(), - background: $.alerts.overlayColor, - opacity: $.alerts.overlayOpacity - }); - break; - case 'hide': - $("#popup_overlay").remove(); - break; - } - }, - - _reposition: function() { - var top = (($(window).height() / 2) - ($("#popup_container").outerHeight() / 2)) + $.alerts.verticalOffset; - var left = (($(window).width() / 2) - ($("#popup_container").outerWidth() / 2)) + $.alerts.horizontalOffset; - if( top < 0 ) top = 0; - if( left < 0 ) left = 0; - - // IE6 fix - if( $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + $(window).scrollTop(); - - $("#popup_container").css({ - top: top + 'px', - left: left + 'px' - }); - $("#popup_overlay").height( $(document).height() ); - }, - - _maintainPosition: function(status) { - if( $.alerts.repositionOnResize ) { - switch(status) { - case true: - $(window).bind('resize', $.alerts._reposition); - break; - case false: - $(window).unbind('resize', $.alerts._reposition); - break; - } - } - } - - } - - // Shortuct functions - jAlert = function(message, title, callback) { - $.alerts.alert(message, title, callback); - } - - jConfirm = function(message, title, callback) { - $.alerts.confirm(message, title, callback); - }; - - jPrompt = function(message, value, title, callback) { - $.alerts.prompt(message, value, title, callback); - }; - -})(jQuery); \ No newline at end of file diff --git a/feincms/static/feincms/style.css b/feincms/static/feincms/style.css index 137a9513f..5a09f5383 100644 --- a/feincms/static/feincms/style.css +++ b/feincms/static/feincms/style.css @@ -211,72 +211,6 @@ td span select { width:600px; } -#popup_bg { - width:100%; height:100%; - background-color:white; - opacity: 0.5; - filter:alpha(opacity=50); - position:absolute; - top:0px; left:0px; -} - - -/* jQuery alerts */ -#popup_container { - font-family: Arial, sans-serif; - font-size: 12px; - min-width: 300px; /* Dialog will be no smaller than this */ - max-width: 600px; /* Dialog will wrap after this width */ - background: #FFF; - border: solid 1px #666; - color: #000; -} - -#popup_title { - font-size: 14px; - font-weight: bold; - text-align: center; - line-height: 1.75em; - color: #666; - background: #eee url(img/title.gif) top repeat-x; - border: solid 1px #FFF; - border-bottom: solid 1px #666; - cursor: default; - padding: 0em; - margin: 0em; -} - -#popup_content { - background: 16px 16px no-repeat url(img/info.gif); - padding: 1em 1.75em; - margin: 0em; -} - -#popup_content.alert { - background-image: url(img/info.gif); -} - -#popup_content.confirm { - background-image: url(img/important.gif); -} - -#popup_content.prompt { - background-image: url(img/help.gif); -} - -#popup_message { - padding-left: 48px; -} - -#popup_panel { - text-align: center; - margin: 1em 0em 0em 1em; -} - -#popup_prompt { - margin: .5em 0em; -} - /* override Django admin styles */ .order-machine fieldset.module > h2{ diff --git a/feincms/templates/admin/feincms/fe_tools.html b/feincms/templates/admin/feincms/fe_tools.html index c2b2f920c..30cf11d03 100644 --- a/feincms/templates/admin/feincms/fe_tools.html +++ b/feincms/templates/admin/feincms/fe_tools.html @@ -5,7 +5,7 @@ (function () { // load jQuery if not yet present if (typeof(feincms) == "undefined") { - var jquery_url = "{% static 'feincms/jquery-1.8.3.min.js' %}"; + var jquery_url = "{% static 'feincms/jquery-1.9.1.min.js' %}"; document.write(unescape('%3Cscript src="' + jquery_url + '" type="text/javascript"%3E%3C/script%3E')); } })(); @@ -21,8 +21,8 @@ }; </script> -<script src="{% static 'feincms//frontend_editing.js' %}" type="text/javascript" charset="utf-8"></script> -<link rel="stylesheet" href="{% static 'feincms//frontend_editing.css' %}" type="text/css" media="screen" charset="utf-8"> +<script src="{% static 'feincms/frontend_editing.js' %}" type="text/javascript" charset="utf-8"></script> +<link rel="stylesheet" href="{% static 'feincms/frontend_editing.css' %}" type="text/css" media="screen" charset="utf-8"> <div id="fe_controls"> <a href="?frontend_editing=0">{% trans "Stop Editing" %}</a> diff --git a/feincms/templates/admin/feincms/load-jquery.include b/feincms/templates/admin/feincms/load-jquery.include index 62dd22b53..aa922fe6e 100644 --- a/feincms/templates/admin/feincms/load-jquery.include +++ b/feincms/templates/admin/feincms/load-jquery.include @@ -1,12 +1,11 @@ {% load staticfiles %} {% comment %} -Include jquery, override this template if you want to use a cdn version +Include jquery, override this template if you want to use a cdn version or load more plugins or whatnot {% endcomment %} -<script type="text/javascript" src="{% static 'feincms/jquery-1.8.3.min.js' %}"></script> -<script type="text/javascript" src="{% static 'feincms/jquery-ui-1.8.22.custom.min.js' %}"></script> -<script type="text/javascript" src="{% static 'feincms/jquery.alerts.js' %}"></script> +<script type="text/javascript" src="{% static 'feincms/jquery-1.9.1.min.js' %}"></script> +<script type="text/javascript" src="{% static 'feincms/jquery-ui-1.10.3.custom.min.js' %}"></script> <script type="text/javascript"> var feincms = { From 4efc5373b6ae3c6b5d7204ab3fd500a76c63d5b0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 18 Nov 2013 12:16:42 +0100 Subject: [PATCH 0850/1590] Add a note to the release notes concerning the update of jQuery (UI) --- docs/releases/1.9.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index 19d42572a..e198a12bd 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -38,6 +38,10 @@ New deprecations Notable features and improvements ================================= +* The bundled versions of jQuery and jQuery UI have been updated to 1.9.1 + and 1.10.3 respectively. Custom confirmation boxes have been removed + and standard ones are used instead now. + Bugfixes ======== From 08014adabe659fbcbb08a7c2ddccaa9f68134acc Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Tue, 19 Nov 2013 12:07:22 +0100 Subject: [PATCH 0851/1590] Extract tab construction to own function, so one can reuse it for other tabs. --- feincms/static/feincms/item_editor.js | 33 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index b9dc52874..da38b8751 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -337,24 +337,37 @@ if(!Array.indexOf) { }); } - // global variable holding the current template key - var current_template; - - $(document).ready(function($){ - hide_form_rows_with_hidden_widgets(); + function create_tabbed(_tab_selector, _main_selector, _switch_cb) { + var tab_selector = _tab_selector, + main_selector = _main_selector, + switch_cb = _switch_cb; - $("#main_wrapper > .navi_tab").click(function(){ + $(tab_selector + " > .navi_tab").click(function() { var elem = $(this); - $("#main_wrapper > .navi_tab").removeClass("tab_active"); + $(tab_selector + " > .navi_tab").removeClass("tab_active"); elem.addClass("tab_active"); - $("#main > div:visible, #main > fieldset:visible").hide(); + $(main_selector + " > div:visible, " + main_selector + " > fieldset:visible").hide(); var tab_str = elem.attr("id").substr(0, elem.attr("id").length-4); $('#'+tab_str+'_body').show(); - ACTIVE_REGION = REGION_MAP.indexOf(tab_str); + if(switch_cb) { + switch_cb(tab_str); + } + }); + + } + + // global variable holding the current template key + var current_template; + + $(document).ready(function($){ + hide_form_rows_with_hidden_widgets(); + + create_tabbed('#main_wrapper', '#main', function(tab_str){ + ACTIVE_REGION = REGION_MAP.indexOf(tab_str); // make it possible to open current tab on page reload - window.location.replace('#tab_'+tab_str); + window.location.replace('#tab_'+tab_str); }); // save content type selects for later use From 6e0f502cea258d74fefe3ca968de953a975afa24 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Tue, 19 Nov 2013 13:43:49 +0100 Subject: [PATCH 0852/1590] Morph extensions options into a tab-bar. --- feincms/static/feincms/item_editor.js | 34 +++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index da38b8751..3ee361d54 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -342,7 +342,7 @@ if(!Array.indexOf) { main_selector = _main_selector, switch_cb = _switch_cb; - $(tab_selector + " > .navi_tab").click(function() { + $(tab_selector + " > .navi_tab").on('click', function() { var elem = $(this); $(tab_selector + " > .navi_tab").removeClass("tab_active"); elem.addClass("tab_active"); @@ -355,7 +355,6 @@ if(!Array.indexOf) { switch_cb(tab_str); } }); - } // global variable holding the current template key @@ -370,6 +369,37 @@ if(!Array.indexOf) { window.location.replace('#tab_'+tab_str); }); + /* Rearrange the options fieldsets so we can wrap them into a tab bar */ + var options_fieldsets = $('fieldset.collapse'); + options_fieldsets.wrapAll('<fieldset class="module aligned"><div id="extension_options_wrapper" /></fieldset>'); + var option_wrapper = $('#extension_options_wrapper'); + var panels = []; + + options_fieldsets.each(function(idx, elem) { + var option_title = $('h2', $(elem)).text(); + var c = $(elem).children('div'); + var id_base = 'extension_option_'+ idx; + + $(elem).remove(); + + var paren = option_title.indexOf(' ('); + if(paren > 0) + option_title = option_title.substr(0, paren); + + option_wrapper.append('<div class="navi_tab" id="'+ id_base +'_tab">' + + option_title + + '</div>'); + var panel = $('<div style="clear: both; display: none" id="' + id_base + '_body"></div>'); + panel.html(c); + panels.push(panel); + }); + + option_wrapper.append('<div id="extension_options" />'); + $('#extension_options').html(panels); + + create_tabbed('#extension_options_wrapper', '#extension_options'); + /* Done morphing extension options into tabs */ + // save content type selects for later use save_content_type_selects(); From 92eb9dff9426e8c28e608b64c861a14ef56e132a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 19 Nov 2013 14:10:55 +0100 Subject: [PATCH 0853/1590] Add a too-small-note to the release notes about the tabbed extension interface --- docs/releases/1.9.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index e198a12bd..02669e76b 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -9,6 +9,13 @@ Major feature 1 =============== +Extensions in the item editor +============================= + +Extension fieldsets are now presented using a tabbed interface in the item +editor as well to raise their visibility. + + Backwards-incompatible changes ============================== From 9d2c14f92b80052be1b59e783860f2eb8cff10dc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 20 Nov 2013 10:20:47 +0100 Subject: [PATCH 0854/1590] Also allow directly passing subclasses of Extension to register_extensions --- feincms/extensions.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 64597f2ca..a7ed6801d 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -34,7 +34,10 @@ def register_extensions(cls, *extensions): extension = None - if isinstance(ext, six.string_types): + if issubclass(ext, Extension): + extension = ext + + elif isinstance(ext, six.string_types): try: extension = get_object(ext) except (AttributeError, ImportError, ValueError): From 5b3add4d0732805ef8bfa7a984de966537471393 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 20 Nov 2013 10:24:16 +0100 Subject: [PATCH 0855/1590] Do not run issubclass on non-classes, exceptions happen --- feincms/extensions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index a7ed6801d..a1df512fa 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -3,6 +3,7 @@ """ from functools import wraps +import inspect from django.contrib import admin from django.core.exceptions import ImproperlyConfigured @@ -34,7 +35,7 @@ def register_extensions(cls, *extensions): extension = None - if issubclass(ext, Extension): + if inspect.isclass(ext) and issubclass(ext, Extension): extension = ext elif isinstance(ext, six.string_types): From f755c6ba85cb6a1a34e43c54a710f824c716fdee Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 20 Nov 2013 13:14:41 +0100 Subject: [PATCH 0856/1590] Navigation extension: Do not return the navigation extension base class itself --- feincms/module/page/extensions/navigation.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 3d4aa57f5..72fd6c967 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -95,7 +95,9 @@ def children(self, page, **kwargs): def navigation_extension_choices(): for ext in NavigationExtension.types: - yield ('%s.%s' % (ext.__module__, ext.__name__), ext.name) + if (issubclass(ext, NavigationExtension) + and not ext is NavigationExtension): + yield ('%s.%s' % (ext.__module__, ext.__name__), ext.name) class Extension(extensions.Extension): From e7fae2b515282954e8e2879377297499004ee10b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 11:52:40 +0100 Subject: [PATCH 0857/1590] Extension options: Tab selector should be outside the border --- feincms/static/feincms/item_editor.js | 8 +++++--- feincms/static/feincms/style.css | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 3ee361d54..2a3239e4e 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -342,6 +342,8 @@ if(!Array.indexOf) { main_selector = _main_selector, switch_cb = _switch_cb; + $(tab_selector).addClass('clearfix'); + $(tab_selector + " > .navi_tab").on('click', function() { var elem = $(this); $(tab_selector + " > .navi_tab").removeClass("tab_active"); @@ -366,12 +368,12 @@ if(!Array.indexOf) { create_tabbed('#main_wrapper', '#main', function(tab_str){ ACTIVE_REGION = REGION_MAP.indexOf(tab_str); // make it possible to open current tab on page reload - window.location.replace('#tab_'+tab_str); + window.location.replace('#tab_'+tab_str); }); /* Rearrange the options fieldsets so we can wrap them into a tab bar */ var options_fieldsets = $('fieldset.collapse'); - options_fieldsets.wrapAll('<fieldset class="module aligned"><div id="extension_options_wrapper" /></fieldset>'); + options_fieldsets.wrapAll('<div id="extension_options_wrapper" />'); var option_wrapper = $('#extension_options_wrapper'); var panels = []; @@ -389,7 +391,7 @@ if(!Array.indexOf) { option_wrapper.append('<div class="navi_tab" id="'+ id_base +'_tab">' + option_title + '</div>'); - var panel = $('<div style="clear: both; display: none" id="' + id_base + '_body"></div>'); + var panel = $('<fieldset class="module aligned" style="clear: both; display: none" id="' + id_base + '_body"></fieldset>'); panel.html(c); panels.push(panel); }); diff --git a/feincms/static/feincms/style.css b/feincms/static/feincms/style.css index 5a09f5383..e3786a9f6 100644 --- a/feincms/static/feincms/style.css +++ b/feincms/static/feincms/style.css @@ -99,6 +99,10 @@ select { margin: 10px 0 30px 0; } +.clearfix { *zoom:1; } +.clearfix:before, .clearfix:after { content: " "; display: table; } +.clearfix:after { clear: both; } + textarea { width: 580px; margin-top:5px; From 14430d55ab095c18c9e36cc528ca2224dbc261b0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 11:59:35 +0100 Subject: [PATCH 0858/1590] Allow hiding the extension options fieldset with a second click --- feincms/static/feincms/item_editor.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 2a3239e4e..6bab031f2 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -345,16 +345,23 @@ if(!Array.indexOf) { $(tab_selector).addClass('clearfix'); $(tab_selector + " > .navi_tab").on('click', function() { - var elem = $(this); - $(tab_selector + " > .navi_tab").removeClass("tab_active"); - elem.addClass("tab_active"); - $(main_selector + " > div:visible, " + main_selector + " > fieldset:visible").hide(); + var elem = $(this) + tab_str = elem.attr("id").substr(0, elem.attr("id").length-4); + + if (elem.hasClass('tab_active') && tab_str.indexOf('extension_option') != -1) { + elem.removeClass('tab_active'); + $('#' + tab_str + '_body').hide(); + } else { - var tab_str = elem.attr("id").substr(0, elem.attr("id").length-4); - $('#'+tab_str+'_body').show(); + $(tab_selector + " > .navi_tab").removeClass("tab_active"); + elem.addClass("tab_active"); + $(main_selector + " > div:visible, " + main_selector + " > fieldset:visible").hide(); - if(switch_cb) { - switch_cb(tab_str); + $('#'+tab_str+'_body').show(); + + if(switch_cb) { + switch_cb(tab_str); + } } }); } From 53b997d08ba49a2650658800cfcaf2eeb04f7f49 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 12:48:07 +0100 Subject: [PATCH 0859/1590] Do not add tab_str to the global scope Thanks to mjl for the report. --- feincms/static/feincms/item_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 6bab031f2..db87fea8c 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -345,7 +345,7 @@ if(!Array.indexOf) { $(tab_selector).addClass('clearfix'); $(tab_selector + " > .navi_tab").on('click', function() { - var elem = $(this) + var elem = $(this), tab_str = elem.attr("id").substr(0, elem.attr("id").length-4); if (elem.hasClass('tab_active') && tab_str.indexOf('extension_option') != -1) { From e257af27bf9d62871a00abf1b49da63fcafa2ead Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 14:46:29 +0100 Subject: [PATCH 0860/1590] Merge toolbox.js into fein_tree.js --- feincms/static/feincms/fein_tree.js | 68 +++++++++++++-- feincms/static/feincms/toolbox.js | 82 ------------------- .../templates/admin/feincms/tree_editor.html | 1 - 3 files changed, 61 insertions(+), 90 deletions(-) delete mode 100644 feincms/static/feincms/toolbox.js diff --git a/feincms/static/feincms/fein_tree.js b/feincms/static/feincms/fein_tree.js index 5b8946d42..0e66fe7bd 100755 --- a/feincms/static/feincms/fein_tree.js +++ b/feincms/static/feincms/fein_tree.js @@ -3,6 +3,47 @@ document.write('<style type="text/css">#result_list { display: none }</style>'); +// https://docs.djangoproject.com/en/1.4/ref/contrib/csrf/ +function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); +} +feincms.jQuery.ajaxSetup({ + crossDomain: false, // obviates need for sameOrigin test + beforeSend: function(xhr, settings) { + if (!csrfSafeMethod(settings.type)) { + xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); + } + } +}); + +/* OnClick handler to toggle a boolean field via AJAX */ +function inplace_toggle_boolean(item_id, attr) { + var $ = feincms.jQuery, + deferred = $.Deferred(); + + $.ajax({ + url: ".", + type: "POST", + dataType: "json", + data: { '__cmd': 'toggle_boolean', 'item_id': item_id, 'attr': attr }, + + success: function(data) { + $.each(data, function(i, html) { + var r_id = $(html).attr('id'); + $('#' + r_id).replaceWith(html); + }); + deferred.resolve(); + }, + + error: function(xhr, status, err) { + alert("Unable to toggle " + attr + ": " + xhr.responseText); + } + }); + + return deferred.promise(); +} + feincms.jQuery(function($){ // recolor tree after expand/collapse $.extend($.fn.recolorRows = function() { @@ -16,6 +57,19 @@ feincms.jQuery(function($){ }); + /* Extract an object id (numeric) from a DOM id. Assumes that a "-" is used + as delimiter. Returns either the id found or 0 if something went wrong. + + extractItemId('foo_bar_baz-327') -> 327 + */ + function extractItemId(elem_id) { + var i = elem_id.indexOf('-'); + if(i >= 0) + return parseInt(elem_id.slice(i+1), 10); + + return 0; + } + function isExpandedNode(id) { return feincms.collapsed_nodes.indexOf(id) == -1; } @@ -66,7 +120,7 @@ feincms.jQuery(function($){ $.extend($.fn.feinTree = function() { $('tr', this).each(function(i, el) { // adds 'children' class to all parents - var pageId = extract_item_id($('.page_marker', el).attr('id')); + var pageId = extractItemId($('.page_marker', el).attr('id')); $(el).attr('id', 'item-' + pageId); if (feincms.tree_structure[pageId].length) { $('.page_marker', el).addClass('children'); @@ -176,8 +230,8 @@ feincms.jQuery(function($){ $("body").bind('mouseup', function(event) { if(moveTo.relativeTo) { - var cutItem = extract_item_id(originalRow.find('.page_marker').attr('id')); - var pastedOn = extract_item_id(moveTo.relativeTo.find('.page_marker').attr('id')); + var cutItem = extractItemId(originalRow.find('.page_marker').attr('id')); + var pastedOn = extractItemId(moveTo.relativeTo.find('.page_marker').attr('id')); // get out early if items are the same if(cutItem != pastedOn) { var isParent = (moveTo.relativeTo.next().attr('rel') > moveTo.relativeTo.attr('rel')); @@ -239,7 +293,7 @@ feincms.jQuery(function($){ if(!item.hasClass('children')) return; - var itemId = extract_item_id(item.attr('id')); + var itemId = extractItemId(item.attr('id')); if(!isExpandedNode(itemId)) { item.removeClass('closed'); @@ -279,7 +333,7 @@ feincms.jQuery(function($){ $('tbody tr', rlist).each(function(i, el) { var marker = $('.page_marker', el); if(marker.hasClass('children')) { - var itemId = extract_item_id(marker.attr('id')); + var itemId = extractItemId(marker.attr('id')); doToggle(itemId, false); marker.addClass('closed'); markNodeAsCollapsed(itemId); @@ -300,7 +354,7 @@ feincms.jQuery(function($){ $('tbody tr', rlist).each(function(i, el) { var marker = $('span.page_marker', el); if(marker.hasClass('children')) { - var itemId = extract_item_id($('span.page_marker', el).attr('id')); + var itemId = extractItemId($('span.page_marker', el).attr('id')); doToggle(itemId, true); marker.removeClass('closed'); markNodeAsExpanded(itemId); @@ -338,7 +392,7 @@ feincms.jQuery(function($){ expandOrCollapseNode($(this).find('.page_marker')); break; case 13: // return - where_to = extract_item_id($('span', this).attr('id')); + where_to = extractItemId($('span', this).attr('id')); document.location = document.location.pathname + where_to + '/' break; default: diff --git a/feincms/static/feincms/toolbox.js b/feincms/static/feincms/toolbox.js deleted file mode 100644 index 7f85bb64e..000000000 --- a/feincms/static/feincms/toolbox.js +++ /dev/null @@ -1,82 +0,0 @@ -/* Contains universally useful functions */ - -/* Extract an object id (numeric) from a DOM id. Assumes that a "-" is used - as delimiter. Returns either the id found or 0 if something went wrong. - - extract_item_id('foo_bar_baz-327') -> 327 - */ -function extract_item_id(elem_id) { - var i = elem_id.indexOf('-'); - if(i >= 0) - return parseInt(elem_id.slice(i+1), 10); - - return 0; -} - -/* Given an html snippet (in text form), parses it to extract the id attribute, - then replace the corresponding element in the page with the snippet. The - first parameter is ignored (so the signature matches what $.each expects). - - replace_element(0, '<div id="replace_me">New Stuff!</div>') - */ -function replace_element(i, html) { - var r_id = $(html).attr('id'); - $('#' + r_id).replaceWith(html); -} - -/* Same as above, but processes an array of html snippets */ -function replace_elements(data) { - $.each(data, replace_element); -} - -/* Setup django csrf-token for ajax calls, necessary since Django 1.2.5 */ -/* See http://docs.djangoproject.com/en/1.2/releases/1.2.5/#csrf-exception-for-ajax-requests */ - -$.ajaxSetup({ - beforeSend: function(xhr, settings) { - function getCookie(name) { - var cookieValue = null; - if (document.cookie && document.cookie !== '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = jQuery.trim(cookies[i]); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) == (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - } - if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) { - // Only send the token to relative URLs i.e. locally. - xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); - } - } -}); - -/* OnClick handler to toggle a boolean field via AJAX */ -function inplace_toggle_boolean(item_id, attr) { - var deferred = $.Deferred(); - - $.ajax({ - url: ".", - type: "POST", - dataType: "json", - data: { '__cmd': 'toggle_boolean', 'item_id': item_id, 'attr': attr }, - - success: function(data) { - replace_elements(data); - deferred.resolve(); - }, - - error: function(xhr, status, err) { - alert("Unable to toggle " + attr + ": " + xhr.responseText); - } - }); - - return deferred.promise(); -} - - diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index 10ca97294..ba660c71d 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -13,7 +13,6 @@ <script type="text/javascript" src="{% static 'feincms/ie_compat.js' %}"></script> <script type="text/javascript" src="{% static 'feincms/jquery.cookie.js' %}"></script> -<script type="text/javascript" src="{% static 'feincms/toolbox.js' %}"></script> <script type="text/javascript" src="{% static 'feincms/fein_tree.js' %}"></script> {% endblock %} From 16feff1748b067296e493b5ce6d9d31bdb7edd0b Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Thu, 21 Nov 2013 15:04:27 +0100 Subject: [PATCH 0861/1590] Pass is_popup_var result in item_editor context, so that e.g. richtext init templates can work with earlier feincms/django versions. This allows external libraries to be compatible to previous versions of feincms by using a construct like: {% with FEINCMS_POPUP_VAR|default:"pop=1" as popup_var %} ..."some_url?{{ popup_var }}"... {% endwith %} --- feincms/admin/item_editor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index a3f105dba..23399f0d6 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -192,6 +192,8 @@ def get_content_type_map(self, request): def get_extra_context(self, request): """ Return extra context parameters for add/change views. """ + from feincms.templatetags.feincms_admin_tags import is_popup_var + extra_context = { 'model': self.model, 'available_templates': getattr( @@ -202,6 +204,7 @@ def get_extra_context(self, request): 'FEINCMS_CONTENT_FIELDSET_NAME': FEINCMS_CONTENT_FIELDSET_NAME, 'FEINCMS_FRONTEND_EDITING': settings.FEINCMS_FRONTEND_EDITING, + 'FEINCMS_POPUP_VAR': is_popup_var(), } for processor in self.model.feincms_item_editor_context_processors: From 1466e04a46e46883f9e66013dddb3974d121552d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 15:01:35 +0100 Subject: [PATCH 0862/1590] Properly separate tree and item editor JavaScript and CSS --- .../feincms/{style.css => item_editor.css} | 18 ------------------ .../feincms/{fein_tree.css => tree_editor.css} | 9 +++++++++ .../feincms/{fein_tree.js => tree_editor.js} | 0 .../templates/admin/feincms/item_editor.html | 2 +- .../templates/admin/feincms/tree_editor.html | 5 ++--- 5 files changed, 12 insertions(+), 22 deletions(-) rename feincms/static/feincms/{style.css => item_editor.css} (93%) rename feincms/static/feincms/{fein_tree.css => tree_editor.css} (77%) rename feincms/static/feincms/{fein_tree.js => tree_editor.js} (100%) diff --git a/feincms/static/feincms/style.css b/feincms/static/feincms/item_editor.css similarity index 93% rename from feincms/static/feincms/style.css rename to feincms/static/feincms/item_editor.css index e3786a9f6..461f10b55 100644 --- a/feincms/static/feincms/style.css +++ b/feincms/static/feincms/item_editor.css @@ -1,7 +1,3 @@ -#changelist { - top: 20px; -} - .navi_tab { float:left; padding: 5px 14px 5px 12px; @@ -89,8 +85,6 @@ border: 1px solid #678; } -th { vertical-align: middle; } - select { max-width: 580px; } @@ -240,18 +234,6 @@ ul.errorlist li li { padding: 0; } -/* tree editor */ - -.page_marker { display:block; text-align: right; float: left; padding: 1px 1px 0 0; } -tr.cut { border: 2px dashed black; opacity: 0.5; } -.title-column { width: 400px; } - -table#result_list :focus { background-color: #ccddff !important; outline: 0px; } - -#page_form { - clear: both; -} - div.order-machine div.inline-related > h3{ display: none; } diff --git a/feincms/static/feincms/fein_tree.css b/feincms/static/feincms/tree_editor.css similarity index 77% rename from feincms/static/feincms/fein_tree.css rename to feincms/static/feincms/tree_editor.css index 182c9396b..fd527afa9 100644 --- a/feincms/static/feincms/fein_tree.css +++ b/feincms/static/feincms/tree_editor.css @@ -1,3 +1,12 @@ +/* tree editor */ + +.page_marker { display:block; text-align: right; float: left; padding: 1px 1px 0 0; } +tr.cut { border: 2px dashed black; opacity: 0.5; } +.title-column { width: 400px; } + +table#result_list :focus { background-color: #ccddff !important; outline: 0px; } + + .drag_handle { width: 16px; height: 16px; diff --git a/feincms/static/feincms/fein_tree.js b/feincms/static/feincms/tree_editor.js similarity index 100% rename from feincms/static/feincms/fein_tree.js rename to feincms/static/feincms/tree_editor.js diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index 5c26dda44..b494415dc 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -6,7 +6,7 @@ {% include "admin/feincms/load-jquery.include" %} {% endblock %} -<link rel="stylesheet" type="text/css" href="{% static 'feincms/style.css' %}" /> +<link rel="stylesheet" type="text/css" href="{% static 'feincms/item_editor.css' %}"> <script type="text/javascript" src="{% static 'feincms/ie_compat.js' %}"></script> <script type="text/javascript" src="{% static 'feincms/item_editor.js' %}"></script> diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index ba660c71d..c013740e3 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -3,8 +3,7 @@ {% block extrahead %} {{ block.super }} -<link rel="stylesheet" type="text/css" href="{% static 'feincms/style.css' %}" /> -<link rel="stylesheet" type="text/css" href="{% static 'feincms/fein_tree.css' %}" /> +<link rel="stylesheet" type="text/css" href="{% static 'feincms/tree_editor.css' %}"> {% include "admin/feincms/load-jquery.include" %} <script type="text/javascript"> @@ -13,7 +12,7 @@ <script type="text/javascript" src="{% static 'feincms/ie_compat.js' %}"></script> <script type="text/javascript" src="{% static 'feincms/jquery.cookie.js' %}"></script> -<script type="text/javascript" src="{% static 'feincms/fein_tree.js' %}"></script> +<script type="text/javascript" src="{% static 'feincms/tree_editor.js' %}"></script> {% endblock %} From 52f8982406ae1305536246856504b8d968148a3b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 15:32:18 +0100 Subject: [PATCH 0863/1590] Mostly stop polluting the window namespace in tree_editor.js --- feincms/admin/tree_editor.py | 12 ++-- feincms/static/feincms/tree_editor.js | 82 +++++++++++++-------------- 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index c75ae35d6..bd422ca48 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -109,12 +109,12 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): else: value = getattr(item, attr) a = [ - '<input type="checkbox"', - value and ' checked="checked"' or '', - ' onclick="inplace_toggle_boolean(%d, \'%s\').then($.fn.recolorRows);"' % (item.pk, attr), - ' />', - text, - ] + '<input type="checkbox" data-inplace data-inplace-id="%s"' + ' data-inplace-attribute="%s" %s>' % ( + item.pk, + attr, + 'checked="checked"' if value else '', + )] a.insert(0, '<div id="wrap_%s_%d">' % (attr, item.pk)) a.append('</div>') diff --git a/feincms/static/feincms/tree_editor.js b/feincms/static/feincms/tree_editor.js index 0e66fe7bd..46016b4e9 100755 --- a/feincms/static/feincms/tree_editor.js +++ b/feincms/static/feincms/tree_editor.js @@ -1,62 +1,58 @@ - -/* Suppress initial rendering of result list, but only if we can show it with JS later on */ +// Suppress initial rendering of result list, but only if we can show it with +// JS later on. document.write('<style type="text/css">#result_list { display: none }</style>'); - // https://docs.djangoproject.com/en/1.4/ref/contrib/csrf/ -function csrfSafeMethod(method) { - // these HTTP methods do not require CSRF protection - return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); -} feincms.jQuery.ajaxSetup({ - crossDomain: false, // obviates need for sameOrigin test + crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { - if (!csrfSafeMethod(settings.type)) { + if (!(/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type))) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } } }); -/* OnClick handler to toggle a boolean field via AJAX */ -function inplace_toggle_boolean(item_id, attr) { - var $ = feincms.jQuery, - deferred = $.Deferred(); - - $.ajax({ - url: ".", - type: "POST", - dataType: "json", - data: { '__cmd': 'toggle_boolean', 'item_id': item_id, 'attr': attr }, - - success: function(data) { - $.each(data, function(i, html) { - var r_id = $(html).attr('id'); - $('#' + r_id).replaceWith(html); - }); - deferred.resolve(); - }, - - error: function(xhr, status, err) { - alert("Unable to toggle " + attr + ": " + xhr.responseText); - } - }); - - return deferred.promise(); -} - feincms.jQuery(function($){ // recolor tree after expand/collapse $.extend($.fn.recolorRows = function() { - $('tr:visible:even', this).removeClass('row2').addClass('row1'); - $('tr:visible:odd', this).removeClass('row1').addClass('row2'); + $('tr:visible:even', this).removeClass('row1').addClass('row2'); + $('tr:visible:odd', this).removeClass('row2').addClass('row1'); /* Mark inactive rows */ $('tr.item_inactive').removeClass('item_inactive'); $('div[id^=wrap_active_] input:checkbox:not(:checked)').parents('tr').addClass('item_inactive'); $('div[id^=wrap_active_] img').parents('tr').addClass('item_inactive'); + }); + + $(document.body).on('click', '[data-inplace]', function() { + var elem = $(this), + id = elem.data('inplace-id'), + attr = elem.data('inplace-attribute'); + + $.ajax({ + url: ".", + type: "POST", + dataType: "json", + data: { + '__cmd': 'toggle_boolean', + 'item_id': id, + 'attr': attr + }, + success: function(data) { + $.each(data, function(i, html) { + var r_id = $(html).attr('id'); + $('#' + r_id).replaceWith(html); + }); + $('#result_list tbody').recolorRows(); + }, + error: function(xhr, status, err) { + alert("Unable to toggle " + attr + ": " + xhr.responseText); + } + }); }); + /* Extract an object id (numeric) from a DOM id. Assumes that a "-" is used as delimiter. Returns either the id found or 0 if something went wrong. @@ -133,10 +129,10 @@ feincms.jQuery(function($){ }); $('div.drag_handle').bind('mousedown', function(event) { - BEFORE = 0; - AFTER = 1; - CHILD = 2; - CHILD_PAD = 20; + var BEFORE = 0; + var AFTER = 1; + var CHILD = 2; + var CHILD_PAD = 20; var originalRow = $(event.target).closest('tr'); var rowHeight = originalRow.height(); var childEdge = $(event.target).offset().left + $(event.target).width(); @@ -401,7 +397,7 @@ feincms.jQuery(function($){ } // fire! - rlist = $("#result_list"); + var rlist = $("#result_list"); if($('tbody tr', rlist).length > 1) { rlist.hide(); $('tbody', rlist).feinTree(); From 92b99b0f8cf7a19ce3ee79b66e9b4720903b8cbd Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 16:12:02 +0100 Subject: [PATCH 0864/1590] Two negligible cleanups in item_editor.js --- feincms/static/feincms/item_editor.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index db87fea8c..5cb8a23c1 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -1,14 +1,3 @@ -if(!Array.indexOf) { - Array.prototype.indexOf = function(obj) { - for(var i=0; i<this.length; i++) { - if(this[i]==obj) { - return i; - } - } - return -1; - }; -} - (function($){ // Patch up urlify maps to generate nicer slugs in german if(typeof(Downcoder) != "undefined"){ @@ -620,7 +609,7 @@ if(!Array.indexOf) { } }); - $(window).load(function(){init_contentblocks();}); + $(window).load(init_contentblocks); // externally accessible helpers window.ItemEditor = { From c64ea1fb26fd658d6cf22b7b066674b164231e4f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 16:26:12 +0100 Subject: [PATCH 0865/1590] Add a note that Page.cache_key is not used by FeinCMS itself Refs #492. --- feincms/module/page/models.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 42ddf1064..c77a6ed5c 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -182,11 +182,6 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): _cached_url = models.CharField(_('Cached URL'), max_length=255, blank=True, editable=False, default='', db_index=True) - cache_key_components = [ - lambda p: getattr(django_settings, 'SITE_ID', 0), - lambda p: p._django_content_type.id, - lambda p: p.id] - class Meta: ordering = ['tree_id', 'lft'] abstract = True @@ -319,10 +314,19 @@ def get_navigation_url(self): return self._cached_url return self.redirect_to + cache_key_components = [ + lambda p: getattr(django_settings, 'SITE_ID', 0), + lambda p: p._django_content_type.id, + lambda p: p.id, + ] + def cache_key(self): """ Return a string that may be used as cache key for the current page. The cache_key is unique for each content type and content instance. + + This function is here purely for your convenience. FeinCMS itself + does not use it in any way. """ return '-'.join(str(fn(self)) for fn in self.cache_key_components) From e12a9fc7933c5a3c4854c9eb10ac8723baf9ab30 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 16:35:43 +0100 Subject: [PATCH 0866/1590] Move imports to the top of various files --- feincms/admin/item_editor.py | 8 +++----- feincms/content/application/models.py | 2 +- feincms/content/comments/models.py | 13 +++++++------ feincms/contrib/tagging.py | 9 +++------ feincms/module/medialibrary/modeladmins.py | 9 ++++----- feincms/module/medialibrary/zip.py | 5 ++--- feincms/module/page/modeladmins.py | 2 +- feincms/module/page/models.py | 3 +-- feincms/templatetags/applicationcontent_tags.py | 13 ++++++------- feincms/utils/__init__.py | 2 +- 10 files changed, 29 insertions(+), 37 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 23399f0d6..a68780f9d 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -2,10 +2,10 @@ # coding=utf-8 # ------------------------------------------------------------------------ -import re import copy - import logging +import re +import warnings from django import forms, template from django.contrib.admin.options import InlineModelAdmin @@ -21,6 +21,7 @@ from feincms import settings, ensure_completely_loaded from feincms.extensions import ExtensionModelAdmin from feincms.signals import itemeditor_post_save_related +from feincms.templatetags.feincms_admin_tags import is_popup_var # ------------------------------------------------------------------------ @@ -105,7 +106,6 @@ def get_feincms_inlines(self, model, request): attrs['form'] = inline.form if hasattr(content_type, 'feincms_item_editor_form'): - import warnings warnings.warn( 'feincms_item_editor_form on %s is ignored because feincms_item_editor_inline is set too' % content_type, RuntimeWarning) @@ -192,8 +192,6 @@ def get_content_type_map(self, request): def get_extra_context(self, request): """ Return extra context parameters for add/change views. """ - from feincms.templatetags.feincms_admin_tags import is_popup_var - extra_context = { 'model': self.model, 'available_templates': getattr( diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index f0d35dbb4..71ae0285d 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -14,6 +14,7 @@ from django.db.models import signals from django.http import HttpResponse from django.utils.functional import curry as partial, lazy, wraps +from django.utils.http import http_date from django.utils.safestring import mark_safe from django.utils.translation import get_language, ugettext_lazy as _ @@ -338,7 +339,6 @@ def _update_response_headers(self, request, response, headers): Combine all headers that were set by the different content types We are interested in Cache-Control, Last-Modified, Expires """ - from django.utils.http import http_date # Ideally, for the Cache-Control header, we'd want to do some # intelligent combining, but that's hard. Let's just collect and unique diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index a6b4d67a5..9c1a9d148 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -13,12 +13,15 @@ """ from django.contrib import comments +from django.contrib.comments.views.comments import post_comment from django.db import models from django.http import HttpResponseRedirect from django.template import RequestContext from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from feincms.admin.item_editor import ItemEditorForm + # ------------------------------------------------------------------------ class CommentsContent(models.Model): @@ -31,8 +34,6 @@ class Meta: @classmethod def initialize_type(cls): - from feincms.admin.item_editor import ItemEditorForm - class CommentContentAdminForm(ItemEditorForm): def __init__(self, *args, **kwargs): super(CommentContentAdminForm, self).__init__(*args, **kwargs) @@ -65,14 +66,14 @@ def process(self, request, **kwargs): f = None if self.comments_enabled and request.POST: - # I guess the drawback is that this page can't handle any other types of posts - # just the comments for right now, but if we just post to the current path - # and handle it this way .. at least it works for now. + # I guess the drawback is that this page can't handle any other + # types of posts just the comments for right now, but if we just + # post to the current path and handle it this way .. at least it + # works for now. #extra = request._feincms_extra_context.get('page_extra_path', ()) #if len(extra) > 0 and extra[0] == u"post-comment": - from django.contrib.comments.views.comments import post_comment r = post_comment(request, next=comment_page.get_absolute_url()) if isinstance(r, HttpResponseRedirect): diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index b3ef0aefa..cda3d5b3f 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -16,8 +16,10 @@ from django.utils import six from django.utils.translation import ugettext_lazy as _ -from tagging.fields import TagField from tagging import AlreadyRegistered +from tagging.fields import TagField +from tagging.models import Tag +from tagging.utils import parse_tag_input # ------------------------------------------------------------------------ @@ -56,9 +58,6 @@ def __init__(self, filter_horizontal=False, *args, **kwargs): self.filter_horizontal = filter_horizontal def formfield(self, **defaults): - from tagging.models import Tag - from tagging.utils import parse_tag_input - if self.filter_horizontal: widget = FilteredSelectMultiple(self.verbose_name, is_stacked=False) else: @@ -80,8 +79,6 @@ def pre_save_handler(sender, instance, **kwargs): Intercept attempts to save and sort the tag field alphabetically, so we won't have different permutations in the filter list. """ - from tagging.utils import parse_tag_input - taglist = parse_tag_input(instance.tags) instance.tags = taglist_to_string(taglist) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 45112316f..755c7d876 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -22,12 +22,14 @@ from django.utils.translation import ungettext, ugettext_lazy as _ from django.views.decorators.csrf import csrf_protect -from ...translations import admin_translationinline, lookup_translations -from ...extensions import ExtensionModelAdmin +from feincms.extensions import ExtensionModelAdmin +from feincms.translations import admin_translationinline, lookup_translations +from feincms.utils import shorten_string from .models import Category, MediaFileTranslation from .forms import MediaCategoryAdminForm, MediaFileAdminForm from .thumbnail import admin_thumbnail +from .zip import import_zipfile # ----------------------------------------------------------------------- @@ -180,7 +182,6 @@ def file_info(self, obj): the file name later on, this can be used to access the file name from JS, like for example a TinyMCE connector shim. """ - from feincms.utils import shorten_string return u'<input type="hidden" class="medialibrary_file_path" name="_media_path_%d" value="%s" id="_refkey_%d" /> %s <br />%s, %s' % ( obj.id, obj.file.name, @@ -197,8 +198,6 @@ def file_info(self, obj): @csrf_protect @permission_required('medialibrary.add_mediafile') def bulk_upload(request): - from .zip import import_zipfile - if request.method == 'POST' and 'data' in request.FILES: try: count = import_zipfile(request.POST.get('category'), request.POST.get('overwrite', False), request.FILES['data']) diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 36598cb75..10226aa78 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -14,8 +14,9 @@ import os import time -from django.template.defaultfilters import slugify from django.conf import settings as django_settings +from django.core.files.base import ContentFile +from django.template.defaultfilters import slugify from django.utils import timezone from .models import Category, MediaFile, MediaFileTranslation @@ -67,8 +68,6 @@ def import_zipfile(category_id, overwrite, data): count = 0 for zi in z.infolist(): if not zi.filename.endswith('/'): - from django.core.files.base import ContentFile - bname = os.path.basename(zi.filename) if bname and not bname.startswith(".") and "." in bname: fname, ext = os.path.splitext(bname) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 05b84c5c1..4164e1cdc 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -9,6 +9,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.staticfiles.templatetags.staticfiles import static from django.contrib import admin +from django.contrib import messages from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.utils.functional import curry @@ -175,7 +176,6 @@ def change_view(self, request, object_id, **kwargs): try: return super(PageAdmin, self).change_view(request, object_id, **kwargs) except PermissionDenied: - from django.contrib import messages messages.add_message(request, messages.ERROR, _("You don't have the necessary permissions to edit this object")) return HttpResponseRedirect(reverse('admin:page_page_changelist')) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c77a6ed5c..90f1e4828 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -23,7 +23,7 @@ from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin -from feincms.utils import path_to_cache_key +from feincms.utils import path_to_cache_key, shorten_string REDIRECT_TO_RE = re.compile( @@ -219,7 +219,6 @@ def short_title(self): """ Title shortened for display. """ - from feincms.utils import shorten_string return shorten_string(self.title) short_title.admin_order_field = 'title' short_title.short_description = _('title') diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index cb0722250..eb99a6ce5 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -4,8 +4,12 @@ from django.template.defaulttags import kwarg_re from django.utils.encoding import smart_str +from feincms.content.application.models import (ApplicationContent, + app_reverse as do_app_reverse) +from feincms.templatetags.feincms_tags import _render_content # backwards compatibility import -from feincms.templatetags.fragment_tags import fragment, get_fragment, has_fragment +from feincms.templatetags.fragment_tags import (fragment, get_fragment, + has_fragment) register = template.Library() @@ -29,9 +33,6 @@ def feincms_render_region_appcontent(page, region, request): {% feincms_render_region_appcontent feincms_page "main" request %} {% endif %} """ - from feincms.content.application.models import ApplicationContent - from feincms.templatetags.feincms_tags import _render_content - return u''.join(_render_content(content, request=request) for content in page.content.all_of_type(ApplicationContent) if content.region == region) @@ -45,8 +46,6 @@ def __init__(self, view_name, urlconf, args, kwargs, asvar): self.asvar = asvar def render(self, context): - from feincms.content.application.models import app_reverse - args = [arg.resolve(context) for arg in self.args] kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context)) for k, v in self.kwargs.items()]) @@ -54,7 +53,7 @@ def render(self, context): urlconf = self.urlconf.resolve(context) try: - url = app_reverse(view_name, urlconf, args=args, kwargs=kwargs, + url = do_app_reverse(view_name, urlconf, args=args, kwargs=kwargs, current_app=context.current_app) except NoReverseMatch: if self.asvar is None: diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index afc206952..b0661e10b 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -14,6 +14,7 @@ from django.db.models import AutoField from django.db.models import get_model from django.utils import six +from django.utils.encoding import iri_to_uri from django.utils.importlib import import_module from feincms import settings @@ -87,7 +88,6 @@ def path_to_cache_key(path, max_length=200, prefix=""): max key size, so if too long, hash it and use that instead. """ - from django.utils.encoding import iri_to_uri path = iri_to_uri(path) # logic below borrowed from http://richwklein.com/2009/08/04/improving-django-cache-part-ii/ From 9b8fb793cd76f85cb561b0db681549c5b00aeeca Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 22 Nov 2013 10:31:43 +0100 Subject: [PATCH 0867/1590] Do not hardcode the Page in the preview handler Refs #487. --- feincms/contrib/preview/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index d5fee39bc..0d26c15a6 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -1,7 +1,6 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 -from feincms.module.page.models import Page from feincms.views.cbv.views import Handler @@ -17,7 +16,7 @@ class PreviewHandler(Handler): def get_object(self): """Get the page by the id in the url here instead.""" - page = get_object_or_404(Page, pk=self.args[1]) + page = get_object_or_404(self.page_model, pk=self.args[1]) # Remove _preview/42/ from URL, the rest of the handler code should not # know that anything about previewing. Handler.prepare will still raise From bd346cb9e6d007b9dfc55951bbb9ba83a15b9f59 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 22 Nov 2013 10:38:04 +0100 Subject: [PATCH 0868/1590] Relatedpages extension: Reference FEINCMS_DEFAULT_PAGE_MODEL Refs #487. --- feincms/module/page/extensions/relatedpages.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 0e80ca885..506f8d269 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -5,14 +5,13 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -from feincms import extensions -from feincms.module.page.models import Page +from feincms import extensions, settings class Extension(extensions.Extension): def handle_model(self): self.model.add_to_class('related_pages', models.ManyToManyField( - Page, + settings.FEINCMS_DEFAULT_PAGE_MODEL, blank=True, null=True, related_name='%(app_label)s_%(class)s_related', From 6f366337a4f672ba7c524362e4d267539ea9e568 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 22 Nov 2013 11:25:36 +0100 Subject: [PATCH 0869/1590] Wrap a few long lines in tree_editor.py --- feincms/admin/tree_editor.py | 55 +++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index bd422ca48..4e7c93392 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -234,13 +234,17 @@ def __init__(self, *args, **kwargs): opts = self.model._meta self.change_list_template = [ - 'admin/feincms/%s/%s/tree_editor.html' % (opts.app_label, opts.object_name.lower()), + 'admin/feincms/%s/%s/tree_editor.html' % ( + opts.app_label, opts.object_name.lower()), 'admin/feincms/%s/tree_editor.html' % opts.app_label, 'admin/feincms/tree_editor.html', ] - self.object_change_permission = opts.app_label + '.' + opts.get_change_permission() - self.object_add_permission = opts.app_label + '.' + opts.get_add_permission() - self.object_delete_permission = opts.app_label + '.' + opts.get_delete_permission() + self.object_change_permission =\ + opts.app_label + '.' + opts.get_change_permission() + self.object_add_permission =\ + opts.app_label + '.' + opts.get_add_permission() + self.object_delete_permission =\ + opts.app_label + '.' + opts.get_delete_permission() def changeable(self, item): return getattr(item, 'feincms_changeable', True) @@ -308,7 +312,8 @@ def _collect_editable_booleans(self): result_func = item.editable_boolean_result else: def _fn(attr): - return lambda self, instance: [ajax_editable_boolean_cell(instance, attr)] + return lambda self, instance: [ + ajax_editable_boolean_cell(instance, attr)] result_func = _fn(attr) self._ajax_editable_booleans[attr] = result_func @@ -317,7 +322,8 @@ def _refresh_changelist_caches(self): Refresh information used to show the changelist tree structure such as inherited active/inactive states etc. - XXX: This is somewhat hacky, but since it's an internal method, so be it. + XXX: This is somewhat hacky, but since it's an internal method, so be + it. """ pass @@ -333,8 +339,11 @@ def _toggle_boolean(self, request): return HttpResponseBadRequest("Malformed request") if not request.user.is_staff: - logger.warning("Denied AJAX request by non-staff \"%s\" to toggle boolean %s for object #%s", request.user, attr, item_id) - return HttpResponseForbidden(_("You do not have permission to modify this object")) + logger.warning( + "Denied AJAX request by non-staff \"%s\" to toggle boolean" + " %s for object #%s", request.user, attr, item_id) + return HttpResponseForbidden( + _("You do not have permission to modify this object")) self._collect_editable_booleans() @@ -347,8 +356,11 @@ def _toggle_boolean(self, request): return HttpResponseNotFound("Object does not exist") if not self.has_change_permission(request, obj=obj): - logger.warning("Denied AJAX request by \"%s\" to toggle boolean %s for object %s", request.user, attr, item_id) - return HttpResponseForbidden(_("You do not have permission to modify this object")) + logger.warning( + "Denied AJAX request by \"%s\" to toggle boolean %s for" + " object %s", request.user, attr, item_id) + return HttpResponseForbidden( + _("You do not have permission to modify this object")) new_state = not getattr(obj, attr) logger.info("Toggle %s on #%d %s to %s by \"%s\"", @@ -367,8 +379,10 @@ def _toggle_boolean(self, request): data = self._ajax_editable_booleans[attr](self, obj) except Exception: - logger.exception("Unhandled exception while toggling %s on %s", attr, obj) - return HttpResponseServerError("Unable to toggle %s on %s" % (attr, obj)) + logger.exception( + "Unhandled exception while toggling %s on %s", attr, obj) + return HttpResponseServerError( + "Unable to toggle %s on %s" % (attr, obj)) # Weed out unchanged cells to keep the updates small. This assumes # that the order a possible get_descendents() returns does not change @@ -396,17 +410,18 @@ def changelist_view(self, request, extra_context=None, *args, **kwargs): return self._toggle_boolean(request) elif cmd == 'move_node': return self._move_node(request) - else: - return HttpResponseBadRequest('Oops. AJAX request not understood.') + + return HttpResponseBadRequest('Oops. AJAX request not understood.') self._refresh_changelist_caches() extra_context = extra_context or {} queryset = self.queryset(request) - extra_context['tree_structure'] = mark_safe(json.dumps( - _build_tree_structure(queryset))) + extra_context['tree_structure'] = mark_safe( + json.dumps(_build_tree_structure(queryset))) - return super(TreeEditor, self).changelist_view(request, extra_context, *args, **kwargs) + return super(TreeEditor, self).changelist_view( + request, extra_context, *args, **kwargs) def has_add_permission(self, request, obj=None): """ @@ -432,7 +447,8 @@ def has_change_permission(self, request, obj=None): else: r = request.user.has_perm(perm) - return r and super(TreeEditor, self).has_change_permission(request, obj) + return r and super(TreeEditor, self).has_change_permission( + request, obj) def has_delete_permission(self, request, obj=None): """ @@ -445,7 +461,8 @@ def has_delete_permission(self, request, obj=None): else: r = request.user.has_perm(perm) - return r and super(TreeEditor, self).has_delete_permission(request, obj) + return r and super(TreeEditor, self).has_delete_permission( + request, obj) def _move_node(self, request): if hasattr(self.model.objects, 'move_node'): From 94c602afc76023fbb4534df25e12b86d2996da02 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 22 Nov 2013 12:21:02 +0100 Subject: [PATCH 0870/1590] Fix occurrences of E501 --- example/example.db | Bin 99328 -> 99328 bytes example/models.py | 15 +- example/test_utils.py | 33 ----- feincms/admin/filterspecs.py | 38 +++-- feincms/admin/item_editor.py | 92 +++++++----- feincms/admin/tree_editor.py | 5 +- feincms/content/application/models.py | 3 +- feincms/content/comments/models.py | 27 ++-- feincms/content/contactform/models.py | 18 +-- feincms/content/richtext/models.py | 39 ++++-- feincms/content/rss/models.py | 10 +- feincms/content/section/models.py | 3 +- feincms/content/table/models.py | 6 +- feincms/content/template/models.py | 3 +- feincms/content/video/models.py | 4 +- feincms/contrib/fields.py | 6 +- feincms/contrib/preview/views.py | 6 +- feincms/contrib/richtext.py | 3 +- feincms/contrib/tagging.py | 27 ++-- feincms/management/checker.py | 22 ++- .../management/commands/feincms_validate.py | 11 +- feincms/management/commands/rebuild_mptt.py | 4 +- feincms/models.py | 17 ++- .../module/blog/extensions/translations.py | 6 +- feincms/module/blog/models.py | 6 +- feincms/module/extensions/changedate.py | 8 +- feincms/module/extensions/ct_tracker.py | 36 ++--- feincms/module/extensions/datepublisher.py | 17 ++- feincms/module/extensions/translations.py | 68 ++++++--- feincms/module/medialibrary/fields.py | 23 ++- feincms/module/medialibrary/forms.py | 29 ++-- feincms/module/medialibrary/modeladmins.py | 44 ++++-- feincms/module/medialibrary/models.py | 45 ++++-- feincms/module/medialibrary/thumbnail.py | 3 +- feincms/module/medialibrary/zip.py | 34 +++-- feincms/module/page/extensions/navigation.py | 17 ++- .../module/page/extensions/relatedpages.py | 3 +- feincms/module/page/extensions/titles.py | 6 +- feincms/module/page/forms.py | 13 +- feincms/module/page/modeladmins.py | 51 ++++--- feincms/module/page/models.py | 45 +++--- feincms/module/page/processors.py | 17 ++- feincms/module/page/sitemap.py | 12 +- .../page/templatetags/feincms_page_tags.py | 132 +++++++++++------- .../templatetags/applicationcontent_tags.py | 17 ++- feincms/templatetags/feincms_tags.py | 6 +- feincms/templatetags/feincms_thumbnail.py | 7 +- feincms/templatetags/fragment_tags.py | 4 +- feincms/translations.py | 34 +++-- feincms/utils/__init__.py | 11 +- feincms/utils/html/tidy.py | 5 +- feincms/utils/managers.py | 9 +- feincms/utils/queryset_transform.py | 7 +- feincms/utils/templatetags.py | 9 +- feincms/views/cbv/views.py | 6 +- setup.cfg | 4 +- 56 files changed, 707 insertions(+), 419 deletions(-) delete mode 100644 example/test_utils.py diff --git a/example/example.db b/example/example.db index 5c560d7d481a0043f5cdaba2da1bf3422c72748a..1b42d9f2496cf90c29363ef49c9f19e3dcb77402 100644 GIT binary patch delta 315 zcmZqZU~A}Ln;^|7K2gS*QG8=UiMWuFp@M;>m4Shkv9X?snX$RK@#bgZaxy|}On(`e z-I;GQ=P++$R$}_g^mnr$&vPbC6=q+?{A7#7Ji{bYlf;r7gQTLOR0E6jQj4<Otcqd_ zv#eB0UXY^cUG<C#likeyRdX#84KvfyO7io}6H`oz&2q{zjSEZDEX-0&lajJ5EO<c5 zC-WOCG~Y7ce#@Lu%Y}!TVH*Qe7vlnkZH&s31$mZfG^X>i`ZmQn60&;wiCV^uf~LrR mGBY(Y-oBug@in770f$UqRnO>(&}^t@Xl`s`Zn&(0kp%!e$6fmX delta 280 zcmZqZU~A}Ln;^}|KT*b+k$+=CiMWuVxq^X-m7$51fuWwEiKU^5(dK93axwy}%t{Q* z?##EDbC|a=D=|;pEXc#h%%Z~V%Q$^SEu+F@H*<g0swxx1s?4g2s>J*h6C*QAvqUos z(@cX5i$a6!#QaQiE|Buc{Kg8+x6HTSGH29s;bLN3z`)eSxPZACXrK;b8gnyafNx`{ zBO#;ws<I7zLjn!`LmW+kY!m-*w+!DZR|CKBKto@ns7&AR(5lF)KvUnWY-4|y>~g;> u1_p+2zD=cIleaIZWqi#zePu19{Pb1zjIPrw>lk@hO-xJ-jh8hrvH$=+M^Xg< diff --git a/example/models.py b/example/models.py index 719a89db8..ce6fefcda 100644 --- a/example/models.py +++ b/example/models.py @@ -12,7 +12,8 @@ from feincms.content.image.models import ImageContent from feincms.content.medialibrary.models import MediaFileContent from feincms.content.application.models import ApplicationContent -from feincms.module.page.extensions.navigation import NavigationExtension, PagePretender +from feincms.module.page.extensions.navigation import (NavigationExtension, + PagePretender) from feincms.content.application.models import app_reverse @@ -40,7 +41,8 @@ def get_admin_fields(form, *args, **kwargs): label=capfirst(_('exclusive subpages')), required=False, initial=form.instance.parameters.get('exclusive_subpages', False), - help_text=_('Exclude everything other than the application\'s content when rendering subpages.'), + help_text=_('Exclude everything other than the application\'s' + ' content when rendering subpages.'), ), } @@ -74,7 +76,8 @@ def children(self, page, **kwargs): for entry in Entry.objects.all(): yield PagePretender( title=entry.title, - url=app_reverse('blog_entry_detail', 'blog_urls', kwargs={'pk': entry.id}), + url=app_reverse( + 'blog_entry_detail', 'blog_urls', kwargs={'pk': entry.id}), level=page.level + 1, ) @@ -88,7 +91,8 @@ def children(self, page, **kwargs): class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() - parent = models.ForeignKey('self', blank=True, null=True, related_name='children') + parent = models.ForeignKey('self', blank=True, null=True, + related_name='children') class Meta: ordering = ['tree_id', 'lft'] @@ -100,5 +104,6 @@ def __str__(self): # add m2m field to entry so it shows up in entry admin -Entry.add_to_class('categories', models.ManyToManyField(Category, blank=True, null=True)) +Entry.add_to_class('categories', models.ManyToManyField(Category, + blank=True, null=True)) EntryAdmin.list_filter += ('categories',) diff --git a/example/test_utils.py b/example/test_utils.py deleted file mode 100644 index 701f61c2e..000000000 --- a/example/test_utils.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import print_function - -from django.conf import settings -from django.test.simple import DjangoTestSuiteRunner - -import coverage - - -class CoverageRunner(DjangoTestSuiteRunner): - def run_tests(self, *args, **kwargs): - run_with_coverage = hasattr(settings, 'COVERAGE_MODULES') - - if run_with_coverage: - coverage.use_cache(0) - coverage.start() - - result = super(CoverageRunner, self).run_tests(*args, **kwargs) - - if run_with_coverage: - coverage.stop() - print('') - print('----------------------------------------------------------------------') - print(' Unit Test Code Coverage Results') - print('----------------------------------------------------------------------') - coverage_modules = [] - for module in settings.COVERAGE_MODULES: - coverage_modules.append(__import__(module, globals(), - locals(), [''])) - coverage.report(coverage_modules, show_missing=1) - print('----------------------------------------------------------------------') - - return result diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index 681e04b1a..380f1d44e 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -4,7 +4,8 @@ # Authors: Marinho Brandao <marinho at gmail.com> # Guilherme M. Gondim (semente) <semente at taurinus.org> -from django.contrib.admin.filters import FieldListFilter, ChoicesFieldListFilter +from django.contrib.admin.filters import (FieldListFilter, + ChoicesFieldListFilter) from django.utils import six from django.utils.encoding import smart_text from django.utils.safestring import mark_safe @@ -17,17 +18,25 @@ class ParentFieldListFilter(ChoicesFieldListFilter): """ Improved list_filter display for parent Pages by nicely indenting hierarchy - In theory this would work with any mptt model which uses a "title" attribute. + In theory this would work with any mptt model which uses a "title" + attribute. my_model_field.page_parent_filter = True """ - def __init__(self, f, request, params, model, model_admin, field_path=None): - super(ParentFieldListFilter, self).__init__(f, request, params, model, model_admin, field_path) + def __init__(self, f, request, params, model, model_admin, + field_path=None): + super(ParentFieldListFilter, self).__init__( + f, request, params, model, model_admin, field_path) - parent_ids = model.objects.exclude(parent=None).values_list("parent__id", flat=True).order_by("parent__id").distinct() - parents = model.objects.filter(pk__in=parent_ids).values_list("pk", "title", "level") - self.lookup_choices = [(pk, "%s%s" % (" " * level, shorten_string(title, max_length=25))) for pk, title, level in parents] + parent_ids = model.objects.exclude(parent=None).values_list( + "parent__id", flat=True).order_by("parent__id").distinct() + parents = model.objects.filter(pk__in=parent_ids).values_list( + "pk", "title", "level") + self.lookup_choices = [( + pk, + "%s%s" % (" " * level, shorten_string(title, max_length=25)), + ) for pk, title, level in parents] def choices(self, cl): yield { @@ -54,14 +63,17 @@ class CategoryFieldListFilter(ChoicesFieldListFilter): my_model_field.category_filter = True """ - def __init__(self, f, request, params, model, model_admin, field_path=None): - super(CategoryFieldListFilter, self).__init__(f, request, params, model, model_admin, field_path) + def __init__(self, f, request, params, model, model_admin, + field_path=None): + super(CategoryFieldListFilter, self).__init__( + f, request, params, model, model_admin, field_path) # Restrict results to categories which are actually in use: - self.lookup_choices = [ - (i.pk, six.text_type(i)) for i in f.related.parent_model.objects.exclude(**{ - f.related.var_name: None - }) + self.lookup_choices = [( + i.pk, + six.text_type(i)) + for i in f.related.parent_model.objects.exclude( + **{f.related.var_name: None}) ] self.lookup_choices.sort(key=lambda i: i[1]) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index a68780f9d..8bd91a05d 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -72,19 +72,23 @@ def __init__(self, model, admin_site): super(ItemEditor, self).__init__(model, admin_site) def get_inline_instances(self, request, *args, **kwargs): - inline_instances = super(ItemEditor, self).get_inline_instances(request, - *args, **kwargs) + inline_instances = super(ItemEditor, self).get_inline_instances( + request, *args, **kwargs) self.append_feincms_inlines(inline_instances, request) return inline_instances def append_feincms_inlines(self, inline_instances, request): - """ Append generated FeinCMS content inlines to native django inlines. """ + """ + Append generated FeinCMS content inlines to native django inlines. + """ for inline_class in self.get_feincms_inlines(self.model, request): inline_instance = inline_class(self.model, self.admin_site) inline_instances.append(inline_instance) def can_add_content(self, request, content_type): - perm = content_type._meta.app_label + "." + content_type._meta.get_add_permission() + perm = u'.'.join(( + content_type._meta.app_label, + content_type._meta.get_add_permission())) return request.user.has_perm(perm) def get_feincms_inlines(self, model, request): @@ -107,12 +111,14 @@ def get_feincms_inlines(self, model, request): if hasattr(content_type, 'feincms_item_editor_form'): warnings.warn( - 'feincms_item_editor_form on %s is ignored because feincms_item_editor_inline is set too' % content_type, + 'feincms_item_editor_form on %s is ignored because ' + 'feincms_item_editor_inline is set too' % content_type, RuntimeWarning) else: inline = FeinCMSInline - attrs['form'] = getattr(content_type, 'feincms_item_editor_form', inline.form) + attrs['form'] = getattr( + content_type, 'feincms_item_editor_form', inline.form) name = '%sFeinCMSInline' % content_type.__name__ # TODO: We generate a new class every time. Is that really wanted? @@ -120,50 +126,57 @@ def get_feincms_inlines(self, model, request): inlines.append(inline_class) return inlines - def _frontend_editing_view(self, request, cms_id, content_type, content_id): + def _frontend_editing_view(self, request, cms_id, content_type, + content_id): """ - This view is used strictly for frontend editing -- it is not used inside the - standard administration interface. + This view is used strictly for frontend editing -- it is not used + inside the standard administration interface. - The code in feincms/templates/admin/feincms/fe_tools.html knows how to call - this view correctly. + The code in feincms/templates/admin/feincms/fe_tools.html knows how to + call this view correctly. """ try: - model_cls = loading.get_model(self.model._meta.app_label, content_type) + model_cls = loading.get_model( + self.model._meta.app_label, content_type) obj = model_cls.objects.get(parent=cms_id, id=content_id) except: raise Http404() - form_class_base = getattr(model_cls, 'feincms_item_editor_form', ItemEditorForm) + form_class_base = getattr( + model_cls, 'feincms_item_editor_form', ItemEditorForm) ModelForm = modelform_factory(model_cls, exclude=('parent', 'region', 'ordering'), form=form_class_base, - formfield_callback=curry(self.formfield_for_dbfield, request=request)) + formfield_callback=curry( + self.formfield_for_dbfield, request=request)) - # we do not want to edit these two fields in the frontend editing mode; we are - # strictly editing single content blocks there. - # We have to remove them from the form because we explicitly redefined them in - # the ItemEditorForm definition above. Just using exclude is not enough. + # we do not want to edit these two fields in the frontend editing mode; + # we are strictly editing single content blocks there. We have to + # remove them from the form because we explicitly redefined them in the + # ItemEditorForm definition above. Just using exclude is not enough. del ModelForm.base_fields['region'] del ModelForm.base_fields['ordering'] if request.method == 'POST': - # The prefix is used to replace the formset identifier from the ItemEditor - # interface. Customization of the form is easily possible through either matching - # the prefix (frontend editing) or the formset identifier (ItemEditor) as it is - # done in the richtext and mediafile init.html item editor includes. + # The prefix is used to replace the formset identifier from the + # ItemEditor interface. Customization of the form is easily + # possible through either matching the prefix (frontend editing) or + # the formset identifier (ItemEditor) as it is done in the richtext + # and mediafile init.html item editor includes. form = ModelForm(request.POST, instance=obj, prefix=content_type) if form.is_valid(): obj = form.save() - return render_to_response('admin/feincms/fe_editor_done.html', { - 'content': obj.render(request=request), - 'identifier': obj.fe_identifier(), - 'FEINCMS_JQUERY_NO_CONFLICT': settings.FEINCMS_JQUERY_NO_CONFLICT, - }, context_instance=template.RequestContext(request)) + return render_to_response( + 'admin/feincms/fe_editor_done.html', { + 'content': obj.render(request=request), + 'identifier': obj.fe_identifier(), + 'FEINCMS_JQUERY_NO_CONFLICT': + settings.FEINCMS_JQUERY_NO_CONFLICT, + }, context_instance=template.RequestContext(request)) else: form = ModelForm(instance=obj, prefix=content_type) @@ -186,7 +199,8 @@ def get_content_type_map(self, request): for content_type in self.model._feincms_content_types: if self.model == content_type._feincms_content_class: content_name = content_type._meta.verbose_name - content_types.append((content_name, content_type.__name__.lower())) + content_types.append( + (content_name, content_type.__name__.lower())) return content_types def get_extra_context(self, request): @@ -270,21 +284,25 @@ def change_view(self, request, object_id, **kwargs): context.update(self.get_extra_context(request)) context.update(kwargs.get('extra_context', {})) kwargs['extra_context'] = context - return super(ItemEditor, self).change_view(request, object_id, **kwargs) + return super(ItemEditor, self).change_view( + request, object_id, **kwargs) - # The next two add support for sending a "saving done" signal as soon - # as all relevant data have been saved (especially all foreign key relations) + # The next two add support for sending a "saving done" signal as soon as + # all relevant data have been saved (especially all foreign key relations) # This can be used to keep functionality dependend on item content happy. # NOTE: These two can (and probably should) be replaced by overriding # `save_related` as soon as we don't depend on Django<1.4 any more. def response_add(self, request, obj, *args, **kwargs): r = super(ItemEditor, self).response_add(request, obj, *args, **kwargs) - itemeditor_post_save_related.send(sender=obj.__class__, instance=obj, created=True) + itemeditor_post_save_related.send( + sender=obj.__class__, instance=obj, created=True) return r def response_change(self, request, obj, *args, **kwargs): - r = super(ItemEditor, self).response_change(request, obj, *args, **kwargs) - itemeditor_post_save_related.send(sender=obj.__class__, instance=obj, created=False) + r = super(ItemEditor, self).response_change( + request, obj, *args, **kwargs) + itemeditor_post_save_related.send( + sender=obj.__class__, instance=obj, created=False) return r @property @@ -321,6 +339,8 @@ def get_fieldsets(self, request, obj=None): recover_form_template = "admin/feincms/recover_form.html" - def render_revision_form(self, request, obj, version, context, revert=False, recover=False): + def render_revision_form(self, request, obj, version, context, + revert=False, recover=False): context.update(self.get_extra_context(request)) - return super(ItemEditor, self).render_revision_form(request, obj, version, context, revert, recover) + return super(ItemEditor, self).render_revision_form( + request, obj, version, context, revert, recover) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 4e7c93392..ed37580c4 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -216,8 +216,9 @@ class TreeEditor(ExtensionModelAdmin): form = MPTTAdminForm if settings.FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS: - # Make sure that no pagination is displayed. Slicing is disabled anyway, - # therefore this value does not have an influence on the queryset + # Make sure that no pagination is displayed. Slicing is disabled + # anyway, therefore this value does not have an influence on the + # queryset list_per_page = 999999999 def __init__(self, *args, **kwargs): diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 71ae0285d..cc23eb921 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -9,7 +9,8 @@ from django.conf import settings from django.core.cache import cache -from django.core.urlresolvers import Resolver404, resolve, reverse, NoReverseMatch +from django.core.urlresolvers import (Resolver404, resolve, reverse, + NoReverseMatch) from django.db import models from django.db.models import signals from django.http import HttpResponse diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index 9c1a9d148..654bc7b73 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -25,7 +25,8 @@ # ------------------------------------------------------------------------ class CommentsContent(models.Model): - comments_enabled = models.BooleanField(_('enabled'), default=True, help_text=_('New comments may be added')) + comments_enabled = models.BooleanField(_('enabled'), default=True, + help_text=_('New comments may be added')) class Meta: abstract = True @@ -43,14 +44,19 @@ def __init__(self, *args, **kwargs): r = f.help_text r += u'<hr />' comments_model = comments.get_model() - for c in comments_model.objects.for_model(parent.parent).order_by('-submit_date'): - r += '<div class="form-row" style="margin-left: 60px"># %(pk)d <a href="/admin/%(app)s/%(model)s/%(pk)d/">%(comment)s</a> - %(is_public)s</div>' % \ - { - 'pk': c.id, - 'comment': c.comment[:80], - 'is_public': c.is_public and _('public') or _('not public'), - 'app': comments_model._meta.app_label, - 'model': comments_model._meta.module_name + for c in comments_model.objects.for_model( + parent.parent).order_by('-submit_date'): + r += ( + '<div class="form-row" style="margin-left: 60px">' + '# %(pk)d <a href="/admin/%(app)s/%(model)s/%(pk)' + 'd/">%(comment)s</a> - %(is_public)s</div>') % { + 'pk': c.id, + 'comment': c.comment[:80], + 'is_public': ( + _('public') if c.is_public + else _('not public')), + 'app': comments_model._meta.app_label, + 'model': comments_model._meta.module_name, } f.help_text = r @@ -60,7 +66,8 @@ def process(self, request, **kwargs): parent_type = self.parent.__class__.__name__.lower() comment_page = self.parent - if hasattr(comment_page, 'original_translation') and comment_page.original_translation: + if (hasattr(comment_page, 'original_translation') + and comment_page.original_translation): comment_page = comment_page.original_translation f = None diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index 156b4a829..e4ac6b807 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -1,8 +1,8 @@ """ -Simple contact form for FeinCMS. The default form class has name, email, subject -and content fields, content being the only one which is not required. You can -provide your own comment form by passing an additional ``form=YourClass`` -argument to the ``create_content_type`` call. +Simple contact form for FeinCMS. The default form class has name, email, +subject and content fields, content being the only one which is not required. +You can provide your own comment form by passing an additional +``form=YourClass`` argument to the ``create_content_type`` call. """ from django import forms @@ -41,7 +41,8 @@ def initialize_type(cls, form=None): def process(self, request, **kwargs): if request.GET.get('_cf_thanks'): - self.rendered_output = render_to_string('content/contactform/thanks.html', + self.rendered_output = render_to_string( + 'content/contactform/thanks.html', context_instance=RequestContext(request)) return @@ -67,9 +68,10 @@ def process(self, request, **kwargs): form = self.form(initial=initial) - self.rendered_output = render_to_string('content/contactform/form.html', { - 'content': self, - 'form': form, + self.rendered_output = render_to_string( + 'content/contactform/form.html', { + 'content': self, + 'form': form, }, context_instance=RequestContext(request)) def render(self, **kwargs): diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 6efb13881..17f425e55 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -28,9 +28,10 @@ def clean(self): cleaned_data = super(RichTextContentAdminForm, self).clean() if settings.FEINCMS_TIDY_HTML: - text, errors, warnings = get_object(settings.FEINCMS_TIDY_FUNCTION)(cleaned_data['text']) + text, errors, warnings = get_object( + settings.FEINCMS_TIDY_FUNCTION)(cleaned_data['text']) - # Ick, but we need to be able to update text and seen_tidy_warnings: + # Ick, but we need to be able to update text and seen_tidy_warnings self.data = self.data.copy() # We always replace the HTML with the tidied version: @@ -39,21 +40,29 @@ def clean(self): if settings.FEINCMS_TIDY_SHOW_WARNINGS and (errors or warnings): if settings.FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE: - # Convert the ignore input from hidden to Checkbox so the user can change it: - self.fields['seen_tidy_warnings'].widget = forms.CheckboxInput() - - if errors or not (settings.FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE and cleaned_data['seen_tidy_warnings']): - self._errors["text"] = ErrorList([mark_safe( - _("HTML validation produced %(count)d warnings. Please review the updated content below before continuing: %(messages)s") % { - "count": len(warnings) + len(errors), - "messages": '<ul><li>%s</li></ul>' % "</li><li>".join(map(escape, errors + warnings)) + # Convert the ignore input from hidden to Checkbox so the + # user can change it: + self.fields['seen_tidy_warnings'].widget =\ + forms.CheckboxInput() + + if errors or not ( + settings.FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE + and cleaned_data['seen_tidy_warnings']): + self._errors["text"] = ErrorList([mark_safe(_( + "HTML validation produced %(count)d warnings." + " Please review the updated content below before" + " continuing: %(messages)s") % { + "count": len(warnings) + len(errors), + "messages": '<ul><li>%s</li></ul>' % ( + "</li><li>".join(map(escape, errors + warnings))), } )]) # If we're allowed to ignore warnings and we don't have any # errors we'll set our hidden form field to allow the user to # ignore warnings on the next submit: - if not errors and settings.FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE: + if (not errors + and settings.FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE): self.data["%s-seen_tidy_warnings" % self.prefix] = True return cleaned_data @@ -115,8 +124,12 @@ def func_im(self, *args, **kwargs): # TODO: Move this into somewhere more generic: if settings.FEINCMS_TIDY_HTML: - # Make sure we can load the tidy function without dependency failures: + # Make sure we can load the tidy function without dependency + # failures: try: get_object(settings.FEINCMS_TIDY_FUNCTION) except ImportError as e: - raise ImproperlyConfigured("FEINCMS_TIDY_HTML is enabled but the HTML tidy function %s could not be imported: %s" % (settings.FEINCMS_TIDY_FUNCTION, e)) + raise ImproperlyConfigured( + "FEINCMS_TIDY_HTML is enabled but the HTML tidy function" + " %s could not be imported: %s" % ( + settings.FEINCMS_TIDY_FUNCTION, e)) diff --git a/feincms/content/rss/models.py b/feincms/content/rss/models.py index 579a5bb78..2cc788d73 100644 --- a/feincms/content/rss/models.py +++ b/feincms/content/rss/models.py @@ -18,10 +18,14 @@ class RSSContent(models.Model): """ title = models.CharField(_('title'), max_length=50, - help_text=_('The rss field is updated several times a day. A change in the title will only be visible on the home page after the next feed update.')) + help_text=_('The rss field is updated several times a day.' + ' A change in the title will only be visible on the home page' + ' after the next feed update.')) link = models.URLField(_('link')) - rendered_content = models.TextField(_('pre-rendered content'), blank=True, editable=False) - last_updated = models.DateTimeField(_('last updated'), blank=True, null=True) + rendered_content = models.TextField(_('pre-rendered content'), blank=True, + editable=False) + last_updated = models.DateTimeField(_('last updated'), + blank=True, null=True) max_items = models.IntegerField(_('max. items'), default=5) class Meta: diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 9b92ad54b..2b1831709 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -62,7 +62,8 @@ def initialize_type(cls, TYPE_CHOICES=None, cleanse=None): @classmethod def get_queryset(cls, filter_args): # Explicitly add nullable FK mediafile to minimize the DB query count - return cls.objects.select_related('parent', 'mediafile').filter(filter_args) + return cls.objects.select_related('parent', 'mediafile').filter( + filter_args) def render(self, **kwargs): if self.mediafile: diff --git a/feincms/content/table/models.py b/feincms/content/table/models.py index fb7a617ce..e4f141987 100644 --- a/feincms/content/table/models.py +++ b/feincms/content/table/models.py @@ -91,8 +91,10 @@ def render(self, **kwargs): def save(self, *args, **kwargs): # XXX ugly, but otherwise the decoder raises exceptions - self.data = self.data.replace('\r', '\\r').replace('\n', '\\n').replace('\t', '\\t') - self.html = self.data and self.FORMATTERS[self.type](json.loads(self.data)) or u'' + self.data = self.data.replace( + '\r', '\\r').replace('\n', '\\n').replace('\t', '\\t') + self.html = self.data and self.FORMATTERS[self.type]( + json.loads(self.data)) or u'' super(TableContent, self).save(*args, **kwargs) save.alters_data = True diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index be79d0fac..d78755b35 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -56,7 +56,8 @@ def initialize_type(cls, TEMPLATE_LOADERS=DEFAULT_TEMPLATE_LOADERS): cls.template_loaders = [find_template_loader(loader) for loader in TEMPLATE_LOADERS if loader] - cls.add_to_class('filename', models.CharField(_('template'), max_length=100, + cls.add_to_class('filename', models.CharField( + _('template'), max_length=100, choices=TemplateChoices(cls.template_loaders))) def render(self, **kwargs): diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index 2d6d941a5..824a9424d 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -10,8 +10,8 @@ class VideoContent(models.Model): Copy-paste a URL to youtube or vimeo into the text box, this content type will automatically generate the necessary embed code. - Other portals aren't supported currently, but would be easy to add if anyone - would take up the baton. + Other portals aren't supported currently, but would be easy to add if + anyone would take up the baton. You should probably use feincms-oembed. """ diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 925931720..81afb7640 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -44,7 +44,8 @@ def to_python(self, value): try: return json.loads(value) except ValueError: - logging.getLogger("feincms.contrib.fields").exception("Unable to deserialize store JSONField data: %s", value) + logging.getLogger("feincms.contrib.fields").exception( + "Unable to deserialize store JSONField data: %s", value) return {} else: assert value is None @@ -55,7 +56,8 @@ def get_prep_value(self, value): return self._flatten_value(value) def value_to_string(self, obj): - """Extract our value from the passed object and return it in string form""" + """Extract our value from the passed object and return it in string + form""" if hasattr(obj, self.attname): value = getattr(obj, self.attname) diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 0d26c15a6..1d81f07ac 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -28,6 +28,8 @@ def get_object(self): def handler(self, request, *args, **kwargs): if not request.user.is_staff: raise Http404('Not found (not allowed)') - response = super(PreviewHandler, self).handler(request, *args, **kwargs) - response['Cache-Control'] = 'no-cache, must-revalidate, no-store, private' + response = super(PreviewHandler, self).handler( + request, *args, **kwargs) + response['Cache-Control'] =\ + 'no-cache, must-revalidate, no-store, private' return response diff --git a/feincms/contrib/richtext.py b/feincms/contrib/richtext.py index 5e9e05c15..8aa41952a 100644 --- a/feincms/contrib/richtext.py +++ b/feincms/contrib/richtext.py @@ -20,7 +20,8 @@ class RichTextField(models.TextField): rich text instead of plain text in the item editor. """ def formfield(self, form_class=RichTextFormField, **kwargs): - return super(RichTextField, self).formfield(form_class=form_class, **kwargs) + return super(RichTextField, self).formfield( + form_class=form_class, **kwargs) try: diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index cda3d5b3f..48afc4e84 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -59,17 +59,22 @@ def __init__(self, filter_horizontal=False, *args, **kwargs): def formfield(self, **defaults): if self.filter_horizontal: - widget = FilteredSelectMultiple(self.verbose_name, is_stacked=False) + widget = FilteredSelectMultiple( + self.verbose_name, is_stacked=False) else: widget = forms.SelectMultiple() def _render(name, value, attrs=None, *args, **kwargs): value = parse_tag_input(value) - return type(widget).render(widget, name, value, attrs, *args, **kwargs) + return type(widget).render(widget, name, value, attrs, + *args, **kwargs) widget.render = _render defaults['widget'] = widget - choices = [(six.text_type(t), six.text_type(t)) for t in Tag.objects.all()] - return TagSelectFormField(choices=choices, required=not self.blank, **defaults) + choices = [( + six.text_type(t), + six.text_type(t)) for t in Tag.objects.all()] + return TagSelectFormField( + choices=choices, required=not self.blank, **defaults) # ------------------------------------------------------------------------ @@ -84,7 +89,9 @@ def pre_save_handler(sender, instance, **kwargs): # ------------------------------------------------------------------------ -def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_field=False, auto_add_admin_field=True, admin_list_display=True): +def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, + select_field=False, auto_add_admin_field=True, + admin_list_display=True): """ tag_model accepts a number of named parameters: @@ -104,9 +111,12 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_fi """ from tagging import register as tagging_register - cls.add_to_class(field_name, (select_field and TagSelectField or TagField)(field_name.capitalize(), blank=True)) + cls.add_to_class(field_name, ( + TagSelectField if select_field else TagField + )(field_name.capitalize(), blank=True)) # use another name for the tag descriptor - # See http://code.google.com/p/django-tagging/issues/detail?id=95 for the reason why + # See http://code.google.com/p/django-tagging/issues/detail?id=95 for the + # reason why try: tagging_register(cls, tag_descriptor_attr='tagging_' + field_name) except AlreadyRegistered: @@ -117,7 +127,8 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, select_fi admin_cls.list_display.append(field_name) admin_cls.list_filter.append(field_name) - if auto_add_admin_field and hasattr(admin_cls, 'add_extension_options'): + if auto_add_admin_field and hasattr( + admin_cls, 'add_extension_options'): admin_cls.add_extension_options(_('Tagging'), { 'fields': (field_name,) }) diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 38104cdb3..7775a4582 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -15,7 +15,8 @@ def check_database_schema(cls, module_name): Please note that you have to connect the return value using strong references. Here's an example how to do this:: - signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) + signals.post_syncdb.connect( + check_database_schema(Page, __name__), weak=False) (Yes, this is a weak attempt at a substitute for South until we find a way to make South work with FeinCMS' dynamic model creation.) @@ -28,7 +29,8 @@ def _fn(sender, **kwargs): cursor = connection.cursor() existing_columns = [row[0] for row in - connection.introspection.get_table_description(cursor, cls._meta.db_table)] + connection.introspection.get_table_description( + cursor, cls._meta.db_table)] missing_columns = [] @@ -41,16 +43,22 @@ def _fn(sender, **kwargs): style = color_style() - print(style.ERROR('The following columns seem to be missing in the database table %s:' % cls._meta.db_table)) + print(style.ERROR( + 'The following columns seem to be missing in the database table' + ' %s:' % cls._meta.db_table)) + for field in missing_columns: print(u'%s:%s%s' % ( style.SQL_KEYWORD(field.column), ' ' * (25 - len(field.column)), - u'%s.%s' % (field.__class__.__module__, field.__class__.__name__), + u'%s.%s' % ( + field.__class__.__module__, field.__class__.__name__), )) - print(style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to' - ' find out what the correct column types are. (Or use south, which is what' - ' you should be doing anyway.)\n' % (cls._meta.app_label))) + print(style.NOTICE( + '\nPlease consult the output of `python manage.py sql %s` to' + ' find out what the correct column types are. (Or use south,' + ' which is what you should be doing anyway.)\n' % ( + cls._meta.app_label))) return _fn diff --git a/feincms/management/commands/feincms_validate.py b/feincms/management/commands/feincms_validate.py index 7b7ee0b9b..ad0586ba4 100644 --- a/feincms/management/commands/feincms_validate.py +++ b/feincms/management/commands/feincms_validate.py @@ -34,12 +34,14 @@ def handle_noargs(self, **options): def validate_base_model(self, model): """ - Validate a subclass of ``feincms.models.Base`` or anything else created - by ``feincms.models.create_base_model`` + Validate a subclass of ``feincms.models.Base`` or anything else + created by ``feincms.models.create_base_model`` """ if not hasattr(model, 'template'): - print(self.style.NOTICE('%s has no template attribute; did you forget register_templates or register_regions?' % model)) + print(self.style.NOTICE( + '%s has no template attribute; did you forget' + ' register_templates or register_regions?' % model)) def validate_content_type(self, model): """ @@ -48,4 +50,5 @@ def validate_content_type(self, model): for base in model.__bases__: if not base._meta.abstract: - print(self.style.NOTICE('One of %s bases, %s, is not abstract' % (model, base))) + print(self.style.NOTICE( + 'One of %s bases, %s, is not abstract' % (model, base))) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index f16f57a40..e61500935 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -15,7 +15,9 @@ class Command(NoArgsCommand): - help = "Run this manually to rebuild your mptt pointers. Only use in emergencies." + help = ( + "Run this manually to rebuild your mptt pointers. Only use in" + " emergencies.") def handle_noargs(self, **options): print("Rebuilding MPTT pointers for Page") diff --git a/feincms/models.py b/feincms/models.py index 04dc5e834..25da55c86 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -61,7 +61,8 @@ class Template(object): CMS object, most commonly a page. """ - def __init__(self, title, path, regions, key=None, preview_image=None, **kwargs): + def __init__(self, title, path, regions, key=None, preview_image=None, + **kwargs): # The key is what will be stored in the database. If key is undefined # use the template path as fallback. if not key: @@ -443,10 +444,16 @@ class Meta: ordering = ['ordering'] def __str__(self): - return u'%s<pk=%s, parent=%s<pk=%s, %s>, region=%s, ordering=%d>' % ( - self.__class__.__name__, self.pk, - self.parent.__class__.__name__, self.parent.pk, self.parent, - self.region, self.ordering) + return ( + u'%s<pk=%s, parent=%s<pk=%s, %s>, region=%s,' + u' ordering=%d>') % ( + self.__class__.__name__, + self.pk, + self.parent.__class__.__name__, + self.parent.pk, + self.parent, + self.region, + self.ordering) def render(self, **kwargs): """ diff --git a/feincms/module/blog/extensions/translations.py b/feincms/module/blog/extensions/translations.py index 72f62251a..f5ef62eea 100644 --- a/feincms/module/blog/extensions/translations.py +++ b/feincms/module/blog/extensions/translations.py @@ -24,7 +24,8 @@ def handle_model(self): blank=True, null=True, verbose_name=_('translation of'), related_name='translations', limit_choices_to={'language': primary_language}, - help_text=_('Leave this empty for entries in the primary language.') + help_text=_( + 'Leave this empty for entries in the primary language.') )) def available_translations(self): @@ -48,7 +49,8 @@ def available_translations_admin(self): ) for page in translations) available_translations_admin.allow_tags = True - available_translations_admin.short_description = _('available translations') + available_translations_admin.short_description =\ + _('available translations') self.model.available_translations_admin = available_translations_admin def handle_modeladmin(self, modeladmin): diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index a0fd72cb7..88497af54 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -32,8 +32,10 @@ class Entry(Base): help_text=_('This is used for the generated navigation too.')) slug = models.SlugField() - published_on = models.DateTimeField(_('published on'), blank=True, null=True, - help_text=_('Will be set automatically once you tick the `published` checkbox above.')) + published_on = models.DateTimeField(_('published on'), + blank=True, null=True, + help_text=_('Will be set automatically once you tick the `published`' + ' checkbox above.')) class Meta: get_latest_by = 'published_on' diff --git a/feincms/module/extensions/changedate.py b/feincms/module/extensions/changedate.py index 89a3cd13a..407570548 100644 --- a/feincms/module/extensions/changedate.py +++ b/feincms/module/extensions/changedate.py @@ -35,10 +35,10 @@ def dt_to_utc_timestamp(dt): class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('creation_date', - models.DateTimeField(_('creation date'), null=True, editable=False)) - self.model.add_to_class('modification_date', - models.DateTimeField(_('modification date'), null=True, editable=False)) + self.model.add_to_class('creation_date', models.DateTimeField( + _('creation date'), null=True, editable=False)) + self.model.add_to_class('modification_date', models.DateTimeField( + _('modification date'), null=True, editable=False)) if hasattr(self.model, 'cache_key_components'): self.model.cache_key_components.append( diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index a8bd06ea9..de89238e3 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -34,32 +34,35 @@ class TrackerContentProxy(ContentProxy): def _fetch_content_type_counts(self): """ - If an object with an empty _ct_inventory is encountered, compute all the - content types currently used on that object and save the list in the - object itself. Further requests for that object can then access that - information and find out which content types are used without resorting - to multiple selects on different ct tables. + If an object with an empty _ct_inventory is encountered, compute all + the content types currently used on that object and save the list in + the object itself. Further requests for that object can then access + that information and find out which content types are used without + resorting to multiple selects on different ct tables. It is therefore important that even an "empty" object does not have an empty _ct_inventory. """ if 'counts' not in self._cache: - if self.item._ct_inventory and \ - self.item._ct_inventory.get('_version_', -1) == INVENTORY_VERSION: + if (self.item._ct_inventory + and self.item._ct_inventory.get('_version_', -1) + == INVENTORY_VERSION): try: - self._cache['counts'] = self._from_inventory(self.item._ct_inventory) + self._cache['counts'] = self._from_inventory( + self.item._ct_inventory) except KeyError: - # It's possible that the inventory does not fit together with the - # current models anymore, f.e. because a content type has been - # removed. + # It's possible that the inventory does not fit together + # with the current models anymore, f.e. because a content + # type has been removed. pass if 'counts' not in self._cache: super(TrackerContentProxy, self)._fetch_content_type_counts() - self.item._ct_inventory = self._to_inventory(self._cache['counts']) + self.item._ct_inventory = self._to_inventory( + self._cache['counts']) if hasattr(self.item, 'invalidate_cache'): self.item.invalidate_cache() @@ -68,16 +71,17 @@ def _fetch_content_type_counts(self): # Run post save handler by hand if hasattr(self.item, 'get_descendants'): - self.item.get_descendants(include_self=False).update(_ct_inventory=None) + self.item.get_descendants(include_self=False).update( + _ct_inventory=None) return self._cache['counts'] def _translation_map(self): cls = self.item.__class__ if not cls in _translation_map_cache: # Prime translation map and cache it in the class. This needs to be - # done late as opposed to at class definition time as not all information - # is ready, especially when we are doing a "syncdb" the ContentType table - # does not yet exist + # done late as opposed to at class definition time as not all + # information is ready, especially when we are doing a "syncdb" the + # ContentType table does not yet exist map = {} for idx, fct in enumerate(self.item._feincms_content_types): dct = ContentType.objects.get_for_model(fct) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 267ecb44f..5f327a097 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -1,7 +1,7 @@ """ Allows setting a date range for when the page is active. Modifies the active() -manager method so that only pages inside the given range are used in the default -views and the template tags. +manager method so that only pages inside the given range are used in the +default views and the template tags. Depends on the page class having a "active_filters" list that will be used by the page's manager to determine which entries are to be considered active. @@ -22,8 +22,8 @@ # ------------------------------------------------------------------------ def format_date(d, if_none=''): """ - Format a date in a nice human readable way: Omit the year if it's the current - year. Also return a default value if no date is passed in. + Format a date in a nice human readable way: Omit the year if it's the + current year. Also return a default value if no date is passed in. """ if d is None: @@ -83,7 +83,8 @@ def handle_model(self): self.model.add_to_class('publication_end_date', models.DateTimeField(_('publication end date'), blank=True, null=True, - help_text=_('Leave empty if the entry should stay active forever.'))) + help_text=_( + 'Leave empty if the entry should stay active forever.'))) self.model.add_to_class('latest_children', latest_children) # Patch in rounding the pub and pub_end dates on save @@ -93,7 +94,8 @@ def granular_save(obj, *args, **kwargs): if obj.publication_date: obj.publication_date = granular_now(obj.publication_date) if obj.publication_end_date: - obj.publication_end_date = granular_now(obj.publication_end_date) + obj.publication_end_date = granular_now( + obj.publication_end_date) orig_save(obj, *args, **kwargs) self.model.save = granular_save @@ -106,7 +108,8 @@ def granular_save(obj, *args, **kwargs): key='datepublisher') # Processor to patch up response headers for expiry date - self.model.register_response_processor(datepublisher_response_processor) + self.model.register_response_processor( + datepublisher_response_processor) def handle_modeladmin(self, modeladmin): def datepublisher_admin(self, obj): diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index ea695efb8..2909de1f8 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -9,9 +9,10 @@ primary language (the first language in settings.LANGUAGES), thereby enabling deeplinks between translated pages. -It is recommended to activate :class:`django.middleware.locale.LocaleMiddleware` -so that the correct language will be activated per user or session even for -non-FeinCMS managed views such as Django's administration tool. +It is recommended to activate +:class:`django.middleware.locale.LocaleMiddleware` so that the correct language +will be activated per user or session even for non-FeinCMS managed views such +as Django's administration tool. """ # ------------------------------------------------------------------------ @@ -39,7 +40,8 @@ def user_has_language_set(request): This is taken later on as an indication that we should not mess with the site's language settings, after all, the user's decision is what counts. """ - if hasattr(request, 'session') and request.session.get('django_language') is not None: + if (hasattr(request, 'session') + and request.session.get('django_language') is not None): return True if django_settings.LANGUAGE_COOKIE_NAME in request.COOKIES: return True @@ -76,7 +78,8 @@ def translation_set_language(request, select_language): # Only do this when request method is GET (mainly, do not abort # POST requests) response = HttpResponseRedirect(request.get_full_path()) - response.set_cookie(django_settings.LANGUAGE_COOKIE_NAME, select_language) + response.set_cookie( + django_settings.LANGUAGE_COOKIE_NAME, select_language) return response @@ -117,7 +120,9 @@ def translations_request_processor_standard(page, request): def get_current_language_code(request): language_code = getattr(request, 'LANGUAGE_CODE', None) if language_code is None: - logger.warning("Could not access request.LANGUAGE_CODE. Is 'django.middleware.locale.LocaleMiddleware' in MIDDLEWARE_CLASSES?") + logger.warning( + "Could not access request.LANGUAGE_CODE. Is 'django.middleware." + "locale.LocaleMiddleware' in MIDDLEWARE_CLASSES?") return language_code @@ -127,21 +132,26 @@ class Extension(extensions.Extension): def handle_model(self): cls = self.model - cls.add_to_class('language', models.CharField(_('language'), max_length=10, - choices=django_settings.LANGUAGES, default=django_settings.LANGUAGES[0][0])) + cls.add_to_class('language', models.CharField(_('language'), + max_length=10, + choices=django_settings.LANGUAGES, + default=django_settings.LANGUAGES[0][0])) cls.add_to_class('translation_of', models.ForeignKey('self', blank=True, null=True, verbose_name=_('translation of'), related_name='translations', limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, - help_text=_('Leave this empty for entries in the primary language.') + help_text=_( + 'Leave this empty for entries in the primary language.') )) if hasattr(cls, 'register_request_processor'): if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": - cls.register_request_processor(translations_request_processor_explicit, + cls.register_request_processor( + translations_request_processor_explicit, key='translations') else: # STANDARD - cls.register_request_processor(translations_request_processor_standard, + cls.register_request_processor( + translations_request_processor_standard, key='translations') if hasattr(cls, 'get_redirect_to_target'): @@ -150,16 +160,19 @@ def handle_model(self): @monkeypatch_method(cls) def get_redirect_to_target(self, request): """ - Find an acceptable redirect target. If this is a local link, then try - to find the page this redirect references and translate it according - to the user's language. This way, one can easily implement a localized - "/"-url to welcome page redirection. + Find an acceptable redirect target. If this is a local link, + then try to find the page this redirect references and + translate it according to the user's language. This way, one + can easily implement a localized "/"-url to welcome page + redirection. """ target = original_get_redirect_to_target(self, request) - if target and target.find('//') == -1: # Not an offsite link http://bla/blubb + if target and target.find('//') == -1: + # Not an offsite link http://bla/blubb try: page = cls.objects.page_for_path(target) - page = page.get_translation(get_current_language_code(request)) + page = page.get_translation( + get_current_language_code(request)) target = page.get_absolute_url() except cls.DoesNotExist: pass @@ -194,7 +207,8 @@ def original_translation(self): @monkeypatch_method(cls) def get_translation(self, language): - return self.original_translation.translations.get(language=language) + return self.original_translation.translations.get( + language=language) def handle_modeladmin(self, modeladmin): @@ -202,7 +216,8 @@ def handle_modeladmin(self, modeladmin): modeladmin, 'translation_of__translations', 'translations') def available_translations_admin(self, page): - translations = dict((p.language, p.id) for p in page.available_translations()) + translations = dict( + (p.language, p.id) for p in page.available_translations()) links = [] @@ -214,19 +229,26 @@ def available_translations_admin(self, page): links.append(u'<a href="%s/" title="%s">%s</a>' % ( translations[key], _('Edit translation'), key.upper())) else: - links.append(u'<a style="color:#baa" href="add/?translation_of=%s&language=%s" title="%s">%s</a>' % ( - page.id, key, _('Create translation'), key.upper())) + links.append( + u'<a style="color:#baa" href="add/?translation_of=' + u'%s&language=%s" title="%s">%s</a>' % ( + page.id, + key, + _('Create translation'), + key.upper())) return u' | '.join(links) available_translations_admin.allow_tags = True available_translations_admin.short_description = _('translations') - modeladmin.__class__.available_translations_admin = available_translations_admin + modeladmin.__class__.available_translations_admin =\ + available_translations_admin if hasattr(modeladmin, 'add_extension_options'): modeladmin.add_extension_options('language', 'translation_of') - modeladmin.list_display.extend(['language', 'available_translations_admin']) + modeladmin.list_display.extend( + ['language', 'available_translations_admin']) modeladmin.list_filter.extend(['language']) modeladmin.raw_id_fields.append('translation_of') diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 95bcabbcd..1313d12a1 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -29,13 +29,16 @@ def __init__(self, original): def label_for_value(self, value): key = self.rel.get_related_field().name try: - obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) + obj = self.rel.to._default_manager.using(self.db).get( + **{key: value}) label = [u' <strong>%s</strong>' % escape( shorten_string(six.text_type(obj)))] image = admin_thumbnail(obj) if image: - label.append(u'<br /><img src="%s" alt="" style="margin:1em 0 0 10em" />' % image) + label.append( + u'<br /><img src="%s" alt="" style="margin:1em 0 0 10em"' + u'/>' % image) return u''.join(label) except (ValueError, self.rel.to.DoesNotExist): @@ -44,11 +47,13 @@ def label_for_value(self, value): class MediaFileForeignKey(models.ForeignKey): """ - Drop-in replacement for Django's ``models.ForeignKey`` which automatically adds a - thumbnail of media files if the media file foreign key is shown using ``raw_id_fields``. + Drop-in replacement for Django's ``models.ForeignKey`` which automatically + adds a thumbnail of media files if the media file foreign key is shown + using ``raw_id_fields``. """ def formfield(self, **kwargs): - if 'widget' in kwargs and isinstance(kwargs['widget'], ForeignKeyRawIdWidget): + if 'widget' in kwargs and isinstance( + kwargs['widget'], ForeignKeyRawIdWidget): kwargs['widget'] = MediaFileForeignKeyRawIdWidget(kwargs['widget']) return super(MediaFileForeignKey, self).formfield(**kwargs) @@ -71,12 +76,16 @@ class AdminFileWithPreviewWidget(AdminFileWidget): tries to render a small thumbnail besides the input field. """ def render(self, name, value, attrs=None): - r = super(AdminFileWithPreviewWidget, self).render(name, value, attrs=attrs) + r = super(AdminFileWithPreviewWidget, self).render( + name, value, attrs=attrs) if value and getattr(value, 'instance', None): image = admin_thumbnail(value.instance) if image: - r = mark_safe((u'<img src="%s" alt="" style="float: left; padding-right: 8px; border-right: 1px solid #ccc; margin-right: 8px">' % image) + r) + r = mark_safe(( + u'<img src="%s" alt="" style="float: left; padding-right:' + u'8px; border-right: 1px solid #ccc; margin-right: 8px"' + u'>' % image) + r) return r diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index f8759e938..01db7f27b 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -24,13 +24,15 @@ class Meta: def clean_parent(self): data = self.cleaned_data['parent'] if data is not None and self.instance in data.path_list(): - raise forms.ValidationError(_("This would create a loop in the hierarchy")) + raise forms.ValidationError( + _("This would create a loop in the hierarchy")) return data def __init__(self, *args, **kwargs): super(MediaCategoryAdminForm, self).__init__(*args, **kwargs) - self.fields['parent'].queryset = self.fields['parent'].queryset.exclude(pk=self.instance.pk) + self.fields['parent'].queryset =\ + self.fields['parent'].queryset.exclude(pk=self.instance.pk) # ------------------------------------------------------------------------ @@ -43,28 +45,33 @@ def __init__(self, *args, **kwargs): super(MediaFileAdminForm, self).__init__(*args, **kwargs) if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: - if not hasattr(self.instance.file.field, '_feincms_generate_filename_patched'): - orig_generate_filename = self.instance.file.field.generate_filename + field = self.instance.file.field + if not hasattr(field, '_feincms_generate_filename_patched'): + original_generate = field.generate_filename def _gen_fname(instance, filename): if instance.id and hasattr(instance, 'original_name'): - logger.info("Overwriting file %s with new data" % instance.original_name) + logger.info("Overwriting file %s with new data" % ( + instance.original_name)) instance.file.storage.delete(instance.original_name) return instance.original_name - return orig_generate_filename(instance, filename) + return original_generate(instance, filename) - self.instance.file.field.generate_filename = _gen_fname - self.instance.file.field._feincms_generate_filename_patched = True + field.generate_filename = _gen_fname + field._feincms_generate_filename_patched = True def clean_file(self): if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: - new_base, new_ext = os.path.splitext(self.cleaned_data['file'].name) + new_base, new_ext = os.path.splitext( + self.cleaned_data['file'].name) old_base, old_ext = os.path.splitext(self.instance.file.name) if new_ext.lower() != old_ext.lower(): - raise forms.ValidationError( - _("Cannot overwrite with different file type (attempt to overwrite a %(old_ext)s with a %(new_ext)s)") % {'old_ext': old_ext, 'new_ext': new_ext}) + raise forms.ValidationError(_( + "Cannot overwrite with different file type (attempt to" + " overwrite a %(old_ext)s with a %(new_ext)s)" + ) % {'old_ext': old_ext, 'new_ext': new_ext}) self.instance.original_name = self.instance.file.name diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 755c7d876..9d11ba4d9 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -70,7 +70,8 @@ class AddCategoryForm(forms.Form): if not form: form = AddCategoryForm(initial={ - '_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME), + '_selected_action': request.POST.getlist( + admin.ACTION_CHECKBOX_NAME), }) return render_to_response('admin/medialibrary/add_to_category.html', { @@ -95,10 +96,12 @@ def save_as_zipfile(modeladmin, request, queryset): messages.error(request, _("ZIP file export failed: %s") % str(e)) return - return HttpResponseRedirect(os.path.join(django_settings.MEDIA_URL, zip_name)) + return HttpResponseRedirect( + os.path.join(django_settings.MEDIA_URL, zip_name)) -save_as_zipfile.short_description = _('Export selected media files as zip file') +save_as_zipfile.short_description = _( + 'Export selected media files as zip file') # ------------------------------------------------------------------------ @@ -108,7 +111,8 @@ class MediaFileAdmin(ExtensionModelAdmin): save_on_top = True date_hierarchy = 'created' inlines = [admin_translationinline(MediaFileTranslation)] - list_display = ['admin_thumbnail', '__str__', 'file_info', 'formatted_created'] + list_display = ['admin_thumbnail', '__str__', 'file_info', + 'formatted_created'] list_display_links = ['__str__'] list_filter = ['type', 'categories'] list_per_page = 25 @@ -121,7 +125,9 @@ def get_urls(self): urls = super(MediaFileAdmin, self).get_urls() my_urls = patterns('', - url(r'^mediafile-bulk-upload/$', self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, name='mediafile_bulk_upload') + url(r'^mediafile-bulk-upload/$', + self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, + name='mediafile_bulk_upload'), ) return my_urls + urls @@ -130,7 +136,8 @@ def changelist_view(self, request, extra_context=None): if extra_context is None: extra_context = {} extra_context['categories'] = Category.objects.order_by('title') - return super(MediaFileAdmin, self).changelist_view(request, extra_context=extra_context) + return super(MediaFileAdmin, self).changelist_view( + request, extra_context=extra_context) def admin_thumbnail(self, obj): image = admin_thumbnail(obj) @@ -158,7 +165,8 @@ def formatted_created(self, obj): def file_type(self, obj): t = obj.filetypes_dict[obj.type] if obj.type == 'image': - # get_image_dimensions is expensive / slow if the storage is not local filesystem (indicated by availability the path property) + # get_image_dimensions is expensive / slow if the storage is not + # local filesystem (indicated by availability the path property) try: obj.file.path except NotImplementedError: @@ -182,7 +190,11 @@ def file_info(self, obj): the file name later on, this can be used to access the file name from JS, like for example a TinyMCE connector shim. """ - return u'<input type="hidden" class="medialibrary_file_path" name="_media_path_%d" value="%s" id="_refkey_%d" /> %s <br />%s, %s' % ( + return ( + u'<input type="hidden" class="medialibrary_file_path"' + u' name="_media_path_%d" value="%s" id="_refkey_%d" />' + u' %s <br />%s, %s' + ) % ( obj.id, obj.file.name, obj.id, @@ -200,20 +212,26 @@ def file_info(self, obj): def bulk_upload(request): if request.method == 'POST' and 'data' in request.FILES: try: - count = import_zipfile(request.POST.get('category'), request.POST.get('overwrite', False), request.FILES['data']) + count = import_zipfile( + request.POST.get('category'), + request.POST.get('overwrite', False), + request.FILES['data']) messages.info(request, _("%d files imported") % count) except Exception as e: - messages.error(request, _("ZIP import failed: %s") % str(e)) + messages.error(request, _("ZIP import failed: %s") % e) else: messages.error(request, _("No input file given")) - return HttpResponseRedirect(reverse('admin:medialibrary_mediafile_changelist')) + return HttpResponseRedirect( + reverse('admin:medialibrary_mediafile_changelist')) def queryset(self, request): - return super(MediaFileAdmin, self).queryset(request).transform(lookup_translations()) + return super(MediaFileAdmin, self).queryset(request).transform( + lookup_translations()) def save_model(self, request, obj, form, change): obj.purge_translation_cache() - return super(MediaFileAdmin, self).save_model(request, obj, form, change) + return super(MediaFileAdmin, self).save_model( + request, obj, form, change) # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index b3a37f074..5633891e6 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -30,7 +30,8 @@ class CategoryManager(models.Manager): on querysets since we can't even __str__ efficiently without it. """ def get_query_set(self): - return super(CategoryManager, self).get_query_set().select_related("parent") + return super(CategoryManager, self).get_query_set().select_related( + "parent") # ------------------------------------------------------------------------ @@ -83,15 +84,20 @@ def path(self): @python_2_unicode_compatible class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): """ - Abstract media file class. Includes the :class:`feincms.models.ExtensionsMixin` - because of the (handy) extension mechanism. + Abstract media file class. Includes the + :class:`feincms.models.ExtensionsMixin` because of the (handy) extension + mechanism. """ - file = models.FileField(_('file'), max_length=255, upload_to=settings.FEINCMS_MEDIALIBRARY_UPLOAD_TO) - type = models.CharField(_('file type'), max_length=12, editable=False, choices=()) - created = models.DateTimeField(_('created'), editable=False, default=timezone.now) + file = models.FileField(_('file'), max_length=255, + upload_to=settings.FEINCMS_MEDIALIBRARY_UPLOAD_TO) + type = models.CharField(_('file type'), max_length=12, editable=False, + choices=()) + created = models.DateTimeField(_('created'), editable=False, + default=timezone.now) copyright = models.CharField(_('copyright'), max_length=200, blank=True) - file_size = models.IntegerField(_("file size"), blank=True, null=True, editable=False) + file_size = models.IntegerField(_("file size"), blank=True, null=True, + editable=False) categories = models.ManyToManyField(Category, verbose_name=_('categories'), blank=True, null=True) @@ -183,7 +189,8 @@ def save(self, *args, **kwargs): super(MediaFileBase, self).save(*args, **kwargs) - logger.info("Saved mediafile %d (%s, type %s, %d bytes)" % (self.id, self.file.name, self.type, self.file_size or 0)) + logger.info("Saved mediafile %d (%s, type %s, %d bytes)" % ( + self.id, self.file.name, self.type, self.file_size or 0)) # User uploaded a new file. Try to get rid of the old file in # storage, to avoid having orphaned files hanging around. @@ -206,17 +213,24 @@ def delete_mediafile(self, name=None): # ------------------------------------------------------------------------ MediaFileBase.register_filetypes( # Should we be using imghdr.what instead of extension guessing? - ('image', _('Image'), lambda f: re.compile(r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), - ('video', _('Video'), lambda f: re.compile(r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv|flv)$', re.IGNORECASE).search(f)), - ('audio', _('Audio'), lambda f: re.compile(r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), + ('image', _('Image'), lambda f: re.compile( + r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), + ('video', _('Video'), lambda f: re.compile( + r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv|flv)$', + re.IGNORECASE).search(f)), + ('audio', _('Audio'), lambda f: re.compile( + r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), ('pdf', _('PDF document'), lambda f: f.lower().endswith('.pdf')), ('swf', _('Flash'), lambda f: f.lower().endswith('.swf')), ('txt', _('Text'), lambda f: f.lower().endswith('.txt')), ('rtf', _('Rich Text'), lambda f: f.lower().endswith('.rtf')), ('zip', _('Zip archive'), lambda f: f.lower().endswith('.zip')), - ('doc', _('Microsoft Word'), lambda f: re.compile(r'\.docx?$', re.IGNORECASE).search(f)), - ('xls', _('Microsoft Excel'), lambda f: re.compile(r'\.xlsx?$', re.IGNORECASE).search(f)), - ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile(r'\.pptx?$', re.IGNORECASE).search(f)), + ('doc', _('Microsoft Word'), lambda f: re.compile( + r'\.docx?$', re.IGNORECASE).search(f)), + ('xls', _('Microsoft Excel'), lambda f: re.compile( + r'\.xlsx?$', re.IGNORECASE).search(f)), + ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile( + r'\.pptx?$', re.IGNORECASE).search(f)), ('other', _('Binary'), lambda f: True), # Must be last ) @@ -229,7 +243,8 @@ class MediaFile(MediaFileBase): @receiver(post_delete, sender=MediaFile) def _mediafile_post_delete(sender, instance, **kwargs): instance.delete_mediafile() - logger.info("Deleted mediafile %d (%s)" % (instance.id, instance.file.name)) + logger.info("Deleted mediafile %d (%s)" % ( + instance.id, instance.file.name)) # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/thumbnail.py b/feincms/module/medialibrary/thumbnail.py index a4cfb560d..577e0fcad 100644 --- a/feincms/module/medialibrary/thumbnail.py +++ b/feincms/module/medialibrary/thumbnail.py @@ -16,5 +16,6 @@ def default_admin_thumbnail(mediafile, dimensions='100x100', **kwargs): def admin_thumbnail(mediafile, dimensions='100x100'): global _cached_thumbnailer if not _cached_thumbnailer: - _cached_thumbnailer = get_object(settings.FEINCMS_MEDIALIBRARY_THUMBNAIL) + _cached_thumbnailer = get_object( + settings.FEINCMS_MEDIALIBRARY_THUMBNAIL) return _cached_thumbnailer(mediafile, dimensions=dimensions) diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 10226aa78..5751e05bd 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -52,12 +52,16 @@ def import_zipfile(category_id, overwrite, data): except: pass - # If meta information, do we need to create any categories? + # If meta information, do we need to create any categories? # Also build translation map for category ids. category_id_map = {} if is_export_file: - for cat in sorted(info.get('categories', []), key=lambda k: k.get('level', 999)): - new_cat, created = Category.objects.get_or_create(slug=cat['slug'], title=cat['title']) + for cat in sorted( + info.get('categories', []), + key=lambda k: k.get('level', 999)): + new_cat, created = Category.objects.get_or_create( + slug=cat['slug'], + title=cat['title']) category_id_map[cat['id']] = new_cat if created and cat.get('parent', 0): parent_cat = category_id_map.get(cat.get('parent', 0), None) @@ -92,7 +96,10 @@ def import_zipfile(category_id, overwrite, data): if overwrite: mf.file.field.upload_to = wanted_dir mf.copyright = info.get('copyright', '') - mf.file.save(target_fname, ContentFile(z.read(zi.filename)), save=False) + mf.file.save( + target_fname, + ContentFile(z.read(zi.filename)), + save=False) mf.save() found_metadata = False @@ -100,13 +107,17 @@ def import_zipfile(category_id, overwrite, data): try: for tr in info['translations']: found_metadata = True - mt, mt_created = MediaFileTranslation.objects.get_or_create(parent=mf, language_code=tr['lang']) + mt, mt_created =\ + MediaFileTranslation.objects.get_or_create( + parent=mf, language_code=tr['lang']) mt.caption = tr['caption'] mt.description = tr.get('description', None) mt.save() # Add categories - mf.categories = (category_id_map[cat_id] for cat_id in info.get('categories', [])) + mf.categories = ( + category_id_map[cat_id] + for cat_id in info.get('categories', [])) except Exception: pass @@ -127,7 +138,8 @@ def import_zipfile(category_id, overwrite, data): # ------------------------------------------------------------------------ def export_zipfile(site, queryset): now = timezone.now() - zip_name = "export_%s_%04d%02d%02d.zip" % (slugify(site.domain), now.year, now.month, now.day) + zip_name = "export_%s_%04d%02d%02d.zip" % ( + slugify(site.domain), now.year, now.month, now.day) zip_data = open(os.path.join(django_settings.MEDIA_ROOT, zip_name), "w") zip_file = zipfile.ZipFile(zip_data, 'w', allowZip64=True) @@ -165,7 +177,13 @@ def export_zipfile(site, queryset): with open(mf.file.path, "r") as file_data: zip_info = zipfile.ZipInfo( filename=mf.file.name, - date_time=(ctime.tm_year, ctime.tm_mon, ctime.tm_mday, ctime.tm_hour, ctime.tm_min, ctime.tm_sec)) + date_time=( + ctime.tm_year, + ctime.tm_mon, + ctime.tm_mday, + ctime.tm_hour, + ctime.tm_min, + ctime.tm_sec)) zip_info.comment = info zip_file.writestr(zip_info, file_data.read()) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 72fd6c967..1bf54e5eb 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -35,8 +35,8 @@ class PagePretender(object): navigation tree. For use as fake navigation page, you should at least define the following - parameters on creation: title, url, level. If using the translation extension, - also add language. + parameters on creation: title, url, level. If using the translation + extension, also add language. """ pk = None @@ -83,11 +83,12 @@ class NavigationExtension(six.with_metaclass(TypeRegistryMetaClass)): def children(self, page, **kwargs): """ - This is the method which must be overridden in every navigation extension. + This is the method which must be overridden in every navigation + extension. - It receives the page the extension is attached to, the depth up to which - the navigation should be resolved, and the current request object if it - is available. + It receives the page the extension is attached to, the depth up to + which the navigation should be resolved, and the current request object + if it is available. """ raise NotImplementedError @@ -109,7 +110,9 @@ def handle_model(self): _('navigation extension'), choices=navigation_extension_choices(), blank=True, null=True, max_length=200, - help_text=_('Select the module providing subpages for this page if you need to customize the navigation.'))) + help_text=_( + 'Select the module providing subpages for this page if' + ' you need to customize the navigation.'))) @monkeypatch_method(self.model) def extended_navigation(self, **kwargs): diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 506f8d269..0bf949a01 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -15,7 +15,8 @@ def handle_model(self): blank=True, null=True, related_name='%(app_label)s_%(class)s_related', - help_text=_('Select pages that should be listed as related content.'))) + help_text=_( + 'Select pages that should be listed as related content.'))) def handle_modeladmin(self, modeladmin): modeladmin.filter_horizontal = list( diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index e5e63ab51..a2a5acc13 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -1,7 +1,7 @@ """ -Sometimes, a single title is not enough, you'd like subtitles, and maybe differing -titles in the navigation and in the <title>-tag. -This extension lets you do that. +Sometimes, a single title is not enough, you'd like subtitles, and maybe +differing titles in the navigation and in the <title>-tag. This extension lets +you do that. """ from django.db import models diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 2a1952cb6..fcb41edc8 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -97,7 +97,9 @@ def __init__(self, *args, **kwargs): if original.parent: try: - data['parent'] = original.parent.get_translation(kwargs['initial']['language']).id + data['parent'] = original.parent.get_translation( + kwargs['initial']['language'] + ).id except self.page_model.DoesNotExist: # ignore this -- the translation does not exist pass @@ -175,8 +177,10 @@ def clean(self): return cleaned_data if cleaned_data['override_url']: - if active_pages.filter(_cached_url=cleaned_data['override_url']).count(): - self._errors['override_url'] = ErrorList([_('This URL is already taken by an active page.')]) + if active_pages.filter( + _cached_url=cleaned_data['override_url']).count(): + self._errors['override_url'] = ErrorList([ + _('This URL is already taken by an active page.')]) del cleaned_data['override_url'] return cleaned_data @@ -194,7 +198,8 @@ def clean(self): new_url = '/%s/' % cleaned_data['slug'] if active_pages.filter(_cached_url=new_url).count(): - self._errors['active'] = ErrorList([_('This URL is already taken by another active page.')]) + self._errors['active'] = ErrorList([ + _('This URL is already taken by another active page.')]) del cleaned_data['active'] if parent and parent.template.enforce_leaf: diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 4164e1cdc..5e1412dec 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -41,13 +41,16 @@ class Media: }), (_('Other options'), { 'classes': ['collapse'], - 'fields': ['template_key', 'parent', 'override_url', 'redirect_to'], + 'fields': ['template_key', 'parent', 'override_url', + 'redirect_to'], }), - # <-- insertion point, extensions appear here, see insertion_index above + # <-- insertion point, extensions appear here, see insertion_index + # above item_editor.FEINCMS_CONTENT_FIELDSET, ] readonly_fields = [] - list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] + list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', + 'template'] list_filter = ['active', 'in_navigation', 'template_key', 'parent'] search_fields = ['title', 'slug'] prepopulated_fields = {'slug': ('title',)} @@ -73,7 +76,8 @@ def __init__(self, model, admin_site): super(PageAdmin, self).__init__(model, admin_site) - in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) + in_navigation_toggle = tree_editor.ajax_editable_boolean( + 'in_navigation', _('in navigation')) def get_readonly_fields(self, request, obj=None): readonly = super(PageAdmin, self).get_readonly_fields(request, obj=obj) @@ -134,7 +138,8 @@ def add_view(self, request, **kwargs): django_settings.LANGUAGES).get(language_code, '') kwargs['extra_context'] = { 'adding_translation': True, - 'title': _('Add %(language)s translation of "%(page)s"') % { + 'title': _( + 'Add %(language)s translation of "%(page)s"') % { 'language': language, 'page': original, }, @@ -144,12 +149,16 @@ def add_view(self, request, **kwargs): return super(PageAdmin, self).add_view(request, **kwargs) def response_add(self, request, obj, *args, **kwargs): - response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) - if 'parent' in request.GET and '_addanother' in request.POST and response.status_code in (301, 302): + response = super(PageAdmin, self).response_add( + request, obj, *args, **kwargs) + if ('parent' in request.GET + and '_addanother' in request.POST + and response.status_code in (301, 302)): # Preserve GET parameters if we are about to add another page response['Location'] += '?parent=%s' % request.GET['parent'] - if 'translation_of' in request.GET and '_copy_content_from_original' in request.POST: + if ('translation_of' in request.GET + and '_copy_content_from_original' in request.POST): # Copy all contents for content_type in obj._feincms_content_types: if content_type.objects.filter(parent=obj).exists(): @@ -158,25 +167,32 @@ def response_add(self, request, obj, *args, **kwargs): return response try: - original = self.model._tree_manager.get(pk=request.GET.get('translation_of')) + original = self.model._tree_manager.get( + pk=request.GET.get('translation_of')) original = original.original_translation obj.copy_content_from(original) obj.save() - self.message_user(request, _('The content from the original translation has been copied to the newly created page.')) + self.message_user(request, _( + 'The content from the original translation has been copied' + ' to the newly created page.')) except (AttributeError, self.model.DoesNotExist): pass return response def _refresh_changelist_caches(self, *args, **kwargs): - self._visible_pages = list(self.model.objects.active().values_list('id', flat=True)) + self._visible_pages = list( + self.model.objects.active().values_list('id', flat=True)) def change_view(self, request, object_id, **kwargs): try: - return super(PageAdmin, self).change_view(request, object_id, **kwargs) + return super(PageAdmin, self).change_view( + request, object_id, **kwargs) except PermissionDenied: - messages.add_message(request, messages.ERROR, _("You don't have the necessary permissions to edit this object")) + messages.add_message(request, messages.ERROR, _( + "You don't have the necessary permissions to edit this object" + )) return HttpResponseRedirect(reverse('admin:page_page_changelist')) def has_delete_permission(self, request, obj=None): @@ -198,11 +214,14 @@ def is_visible_admin(self, page): # parent page's invisibility is inherited if page.id in self._visible_pages: self._visible_pages.remove(page.id) - return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('inherited')) + return tree_editor.ajax_editable_boolean_cell( + page, 'active', override=False, text=_('inherited')) if page.active and not page.id in self._visible_pages: - # is active but should not be shown, so visibility limited by extension: show a "not active" - return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('extensions')) + # is active but should not be shown, so visibility limited by + # extension: show a "not active" + return tree_editor.ajax_editable_boolean_cell( + page, 'active', override=False, text=_('extensions')) return tree_editor.ajax_editable_boolean_cell(page, 'active') is_visible_admin.allow_tags = True diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 90f1e4828..ff8a39686 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -38,7 +38,8 @@ class BasePageManager(models.Manager, ActiveAwareContentManagerMixin): """ # The fields which should be excluded when creating a copy. - exclude_from_copy = ['id', 'tree_id', 'lft', 'rght', 'level', 'redirect_to'] + exclude_from_copy = ['id', 'tree_id', 'lft', 'rght', 'level', + 'redirect_to'] def page_for_path(self, path, raise404=False): """ @@ -96,7 +97,8 @@ def best_match_for_path(self, path, raise404=False): try: page = self.active().filter(_cached_url__in=paths).extra( - select={'_url_length': 'LENGTH(_cached_url)'}).order_by('-_url_length')[0] + select={'_url_length': 'LENGTH(_cached_url)'} + ).order_by('-_url_length')[0] if not page.are_ancestors_active(): raise IndexError('Parents are inactive.') @@ -170,13 +172,16 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): help_text=_('This is used to build the URL for this page')) parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, null=True, related_name='children') - parent.parent_filter = True # Custom list_filter - see admin/filterspecs.py + # Custom list_filter - see admin/filterspecs.py + parent.parent_filter = True in_navigation = models.BooleanField(_('in navigation'), default=False) - override_url = models.CharField(_('override URL'), max_length=255, blank=True, - help_text=_('Override the target URL. Be sure to include slashes at the ' - 'beginning and at the end if it is a local URL. This ' - 'affects both the navigation and subpages\' URLs.')) - redirect_to = models.CharField(_('redirect to'), max_length=255, blank=True, + override_url = models.CharField(_('override URL'), max_length=255, + blank=True, help_text=_( + 'Override the target URL. Be sure to include slashes at the ' + 'beginning and at the end if it is a local URL. This ' + 'affects both the navigation and subpages\' URLs.')) + redirect_to = models.CharField(_('redirect to'), max_length=255, + blank=True, help_text=_('Target URL for automatic redirects' ' or the primary key of a page.')) _cached_url = models.CharField(_('Cached URL'), max_length=255, blank=True, @@ -249,7 +254,8 @@ def save(self, *args, **kwargs): cached_page_urls[self.id] = self._cached_url super(BasePage, self).save(*args, **kwargs) - # Okay, we have changed the page -- remove the old stale entry from the cache + # Okay, we have changed the page -- remove the old stale entry from the + # cache self.invalidate_cache() # If our cached URL changed we need to update all descendants to @@ -388,16 +394,18 @@ def register_default_processors(cls, frontend_editing=False): Register our default request processors for the out-of-the-box Page experience. """ - cls.register_request_processor(processors.redirect_request_processor, - key='redirect') - cls.register_request_processor(processors.extra_context_request_processor, - key='extra_context') + cls.register_request_processor( + processors.redirect_request_processor, key='redirect') + cls.register_request_processor( + processors.extra_context_request_processor, key='extra_context') if frontend_editing: - cls.register_request_processor(processors.frontendediting_request_processor, - key='frontend_editing') - cls.register_response_processor(processors.frontendediting_response_processor, - key='frontend_editing') + cls.register_request_processor( + processors.frontendediting_request_processor, + key='frontend_editing') + cls.register_response_processor( + processors.frontendediting_response_processor, + key='frontend_editing') # ------------------------------------------------------------------------ @@ -408,7 +416,8 @@ class Meta: verbose_name_plural = _('pages') # not yet # permissions = (("edit_page", _("Can edit page metadata")),) -Page.register_default_processors(frontend_editing=settings.FEINCMS_FRONTEND_EDITING) +Page.register_default_processors( + frontend_editing=settings.FEINCMS_FRONTEND_EDITING) signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 69f626509..48b8f87f7 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -109,7 +109,8 @@ def lastmodifier(request, page, *args, **kwargs): # the net effect is that we will be getting a DummyResponse from # the handler if processing is to continue and a non-DummyResponse # (should be a "304 not modified") if the etag matches. - rsp = condition(etag_func=etagger, last_modified_func=lastmodifier)(dummy_response_handler)(request, page) + rsp = condition(etag_func=etagger, last_modified_func=lastmodifier)( + dummy_response_handler)(request, page) # If dummy then don't do anything, if a real response, return and # thus shortcut the request processing. @@ -130,8 +131,9 @@ def etag_response_processor(page, request, response): def debug_sql_queries_response_processor(verbose=False, file=sys.stderr): """ - Attaches a handler which prints the query count (and optionally all individual queries - which have been executed) on the console. Does nothing if ``DEBUG = False``. + Attaches a handler which prints the query count (and optionally all + individual queries which have been executed) on the console. Does nothing + if ``DEBUG = False``. Example:: @@ -149,12 +151,13 @@ def processor(page, request, response): print_sql = lambda x: x try: import sqlparse - print_sql = lambda x: sqlparse.format(x, reindent=True, keyword_case='upper') + print_sql = lambda x: sqlparse.format( + x, reindent=True, keyword_case='upper') except: pass if verbose: - print("--------------------------------------------------------------", file=file) + print("-" * 60, file=file) time = 0.0 i = 0 for q in connection.queries: @@ -164,8 +167,8 @@ def processor(page, request, response): i, q['time'], print_sql(q['sql'])), file=file) time += float(q['time']) - print("--------------------------------------------------------------", file=file) + print("-" * 60, file=file) print("Total: %d queries, %.3f ms" % (i, time), file=file) - print("--------------------------------------------------------------", file=file) + print("-" * 60, file=file) return processor diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index 28c41cfa8..14c2432f9 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -15,7 +15,9 @@ class PageSitemap(Sitemap): The PageSitemap can be used to automatically generate sitemap.xml files for submission to index engines. See http://www.sitemaps.org/ for details. """ - def __init__(self, navigation_only=False, max_depth=0, changefreq=None, queryset=None, filter=None, extended_navigation=False, page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL, *args, **kwargs): + def __init__(self, navigation_only=False, max_depth=0, changefreq=None, + queryset=None, filter=None, extended_navigation=False, + page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL, *args, **kwargs): """ The PageSitemap accepts the following parameters for customisation of the resulting sitemap.xml output: @@ -76,8 +78,12 @@ def items(self): if getattr(page, 'navigation_extension', None): cnt = 0 for p in page.extended_navigation(): - depth_too_deep = self.depth_cutoff > 0 and p.level > self.depth_cutoff - not_in_nav = self.navigation_only and not p.in_navigation + depth_too_deep = ( + self.depth_cutoff > 0 + and p.level > self.depth_cutoff) + not_in_nav = ( + self.navigation_only + and not p.in_navigation) if depth_too_deep or not_in_nav: continue cnt += 1 diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 7c336a5d8..f49124fc8 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -119,16 +119,21 @@ def _navext_filter(iterable): if getattr(elem, 'navigation_extension', None): current_navextension_node = elem try: - for extended in elem.extended_navigation(depth=depth, request=context.get('request')): - # Only return items from the extended navigation which - # are inside the requested level+depth values. The - # "-1" accounts for the differences in MPTT and - # navigation level counting - this_level = getattr(extended, mptt_opts.level_attr, 0) + for extended in elem.extended_navigation( + depth=depth, request=context.get('request')): + # Only return items from the extended navigation + # which are inside the requested level+depth + # values. The "-1" accounts for the differences in + # MPTT and navigation level counting + this_level = getattr( + extended, mptt_opts.level_attr, 0) if this_level < level + depth - 1: yield extended except Exception as e: - logger.warn("feincms_nav caught exception in navigation extension for page %d: %s", current_navextension_node.id, format_exception(e)) + logger.warn( + "feincms_nav caught exception in navigation" + " extension for page %d: %s", + current_navextension_node.id, format_exception(e)) else: current_navextension_node = None @@ -157,7 +162,8 @@ def what(self, page, args): return page.get_ancestors()[level - 1].get_absolute_url() except IndexError: return '#' -register.tag('feincms_parentlink', do_simple_node_with_var_and_args_helper(ParentLinkNode)) +register.tag('feincms_parentlink', + do_simple_node_with_var_and_args_helper(ParentLinkNode)) # ------------------------------------------------------------------------ @@ -171,7 +177,8 @@ class LanguageLinksNode(SimpleAssignmentNodeWithVarAndArgs): Arguments can be any combination of: - * all or existing: Return all languages or only those where a translation exists + * all or existing: Return all languages or only those where a translation + exists * excludecurrent: Excludes the item in the current language from the list * request=request: The current request object, only needed if you are using AppContents and need to append the "extra path" @@ -181,10 +188,11 @@ class LanguageLinksNode(SimpleAssignmentNodeWithVarAndArgs): Example:: - {% feincms_languagelinks for feincms_page as links all,excludecurrent %} - {% for key, name, link in links %} - <a href="{% if link %}{{ link }}{% else %}/{{ key }}/{% endif %}">{% trans name %}</a> - {% endfor %} + {% feincms_languagelinks for feincms_page as links all,excludecurrent %} + {% for key, name, link in links %} + <a href="{% if link %}{{ link }}{% else %}/{{ key }}/{% endif %}"> + {% trans name %}</a> + {% endfor %} """ def what(self, page, args): @@ -198,9 +206,11 @@ def what(self, page, args): request = args.get('request', None) if request: # Trailing path without first slash - trailing_path = request._feincms_extra_context.get('extra_path', '')[1:] + trailing_path = request._feincms_extra_context.get( + 'extra_path', '')[1:] - translations = dict((t.language, t) for t in page.available_translations()) + translations = dict( + (t.language, t) for t in page.available_translations()) translations[page.language] = page links = [] @@ -216,7 +226,8 @@ def what(self, page, args): links.append((key, name, None)) return links -register.tag('feincms_languagelinks', do_simple_assignment_node_with_var_and_args_helper(LanguageLinksNode)) +register.tag('feincms_languagelinks', + do_simple_assignment_node_with_var_and_args_helper(LanguageLinksNode)) # ------------------------------------------------------------------------ @@ -224,13 +235,15 @@ def _translate_page_into(page, language, default=None): """ Return the translation for a given page """ - # Optimisation shortcut: No need to dive into translations if page already what we want + # Optimisation shortcut: No need to dive into translations if page already + # what we want try: if page.language == language: return page if language is not None: - translations = dict((t.language, t) for t in page.available_translations()) + translations = dict( + (t.language, t) for t in page.available_translations()) if language in translations: return translations[language] except AttributeError: @@ -246,19 +259,21 @@ class TranslatedPageNode(SimpleAssignmentNodeWithVarAndArgs): """ :: - {% feincms_translatedpage for feincms_page as feincms_transpage language=en %} + {% feincms_translatedpage for feincms_page as feincms_transpage + language=en %} {% feincms_translatedpage for feincms_page as originalpage %} - {% feincms_translatedpage for some_page as translatedpage language=feincms_page.language %} + {% feincms_translatedpage for some_page as translatedpage + language=feincms_page.language %} This template tag needs the translations extension. Returns the requested translation of the page if it exists. If the language - argument is omitted the primary language will be returned (the first language - specified in settings.LANGUAGES). + argument is omitted the primary language will be returned (the first + language specified in settings.LANGUAGES). - Note: To distinguish between a bare language code and a variable we check whether - settings LANGUAGES contains that code -- so naming a variable "en" will probably - not do what is intended. + Note: To distinguish between a bare language code and a variable we check + whether settings LANGUAGES contains that code -- so naming a variable "en" + will probably not do what is intended. """ def what(self, page, args, default=None): language = args.get('language', None) @@ -268,19 +283,25 @@ def what(self, page, args, default=None): else: if language not in (x[0] for x in settings.LANGUAGES): try: - language = template.Variable(language).resolve(self.render_context) + language = template.Variable(language).resolve( + self.render_context) except template.VariableDoesNotExist: language = settings.LANGUAGES[0][0] return _translate_page_into(page, language, default=default) -register.tag('feincms_translatedpage', do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNode)) +register.tag('feincms_translatedpage', + do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNode)) # ------------------------------------------------------------------------ class TranslatedPageNodeOrBase(TranslatedPageNode): def what(self, page, args): - return super(TranslatedPageNodeOrBase, self).what(page, args, default=getattr(page, 'get_original_translation', page)) -register.tag('feincms_translatedpage_or_base', do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNodeOrBase)) + return super(TranslatedPageNodeOrBase, self).what( + page, args, + default=getattr(page, 'get_original_translation', page)) +register.tag('feincms_translatedpage_or_base', + do_simple_assignment_node_with_var_and_args_helper( + TranslatedPageNodeOrBase)) # ------------------------------------------------------------------------ @@ -289,14 +310,16 @@ def feincms_translated_or_base(pages, language=None): if not hasattr(pages, '__iter__'): pages = [pages] for page in pages: - yield _translate_page_into(page, language, default=page.get_original_translation) + yield _translate_page_into( + page, language, default=page.get_original_translation) # ------------------------------------------------------------------------ @register.inclusion_tag("breadcrumbs.html") def feincms_breadcrumbs(page, include_self=True): """ - Generate a list of the page's ancestors suitable for use as breadcrumb navigation. + Generate a list of the page's ancestors suitable for use as breadcrumb + navigation. By default, generates an unordered list with the id "breadcrumbs" - override breadcrumbs.html to change this. @@ -307,7 +330,8 @@ def feincms_breadcrumbs(page, include_self=True): """ if not page or not isinstance(page, BasePage): - raise ValueError("feincms_breadcrumbs must be called with a valid Page object") + raise ValueError( + "feincms_breadcrumbs must be called with a valid Page object") ancs = page.get_ancestors() @@ -321,7 +345,9 @@ def feincms_breadcrumbs(page, include_self=True): # ------------------------------------------------------------------------ def _is_parent_of(page1, page2): - return page1.tree_id == page2.tree_id and page1.lft < page2.lft and page1.rght > page2.rght + return (page1.tree_id == page2.tree_id + and page1.lft < page2.lft + and page1.rght > page2.rght) @register.filter @@ -342,19 +368,24 @@ def is_parent_of(page1, page2): # ------------------------------------------------------------------------ def _is_equal_or_parent_of(page1, page2): - return page1.tree_id == page2.tree_id and page1.lft <= page2.lft and page1.rght >= page2.rght + return (page1.tree_id == page2.tree_id + and page1.lft <= page2.lft + and page1.rght >= page2.rght) @register.filter def is_equal_or_parent_of(page1, page2): """ - Determines whether a given page is equal to or the parent of another - page. This is especially handy when generating the navigation. The following + Determines whether a given page is equal to or the parent of another page. + This is especially handy when generating the navigation. The following example adds a CSS class ``current`` to the current main navigation entry:: {% for page in navigation %} - <a {% if page|is_equal_or_parent_of:feincms_page %}class="current"{% endif %}> - {{ page.title }}</a> + <a + {% if page|is_equal_or_parent_of:feincms_page %} + class="current" + {% endif %} + >{{ page.title }}</a> {% endfor %} """ try: @@ -405,22 +436,26 @@ def siblings_along_path_to(page_list, page2): if page_list: try: - # Try to avoid hitting the database: If the current page is in_navigation, - # then all relevant pages are already in the incoming list, no need to - # fetch ancestors or children. + # Try to avoid hitting the database: If the current page is + # in_navigation, then all relevant pages are already in the + # incoming list, no need to fetch ancestors or children. - # NOTE: This assumes that the input list actually is complete (ie. comes from - # feincms_nav). We'll cope with the fall-out of that assumption - # when it happens... + # NOTE: This assumes that the input list actually is complete (ie. + # comes from feincms_nav). We'll cope with the fall-out of that + # assumption when it happens... ancestors = [a_page for a_page in page_list if _is_equal_or_parent_of(a_page, page2)] top_level = min((a_page.level for a_page in page_list)) if not ancestors: - # Happens when we sit on a page outside the navigation tree - # so fake an active root page to avoid a get_ancestors() db call + # Happens when we sit on a page outside the navigation tree so + # fake an active root page to avoid a get_ancestors() db call # which would only give us a non-navigation root page anyway. - p = Page(title="dummy", tree_id=-1, parent_id=None, in_navigation=False) + p = Page( + title="dummy", + tree_id=-1, + parent_id=None, + in_navigation=False) ancestors = (p,) siblings = [ @@ -431,7 +466,8 @@ def siblings_along_path_to(page_list, page2): return siblings except (AttributeError, ValueError) as e: - logger.warn("siblings_along_path_to caught exception: %s", format_exception(e)) + logger.warn("siblings_along_path_to caught exception: %s", + format_exception(e)) return () diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index eb99a6ce5..57641821d 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -33,8 +33,10 @@ def feincms_render_region_appcontent(page, region, request): {% feincms_render_region_appcontent feincms_page "main" request %} {% endif %} """ - return u''.join(_render_content(content, request=request) for content in - page.content.all_of_type(ApplicationContent) if content.region == region) + return u''.join( + _render_content(content, request=request) + for content in page.content.all_of_type(ApplicationContent) + if content.region == region) class AppReverseNode(template.Node): @@ -80,12 +82,12 @@ def app_reverse(parser, token): or {% load applicationcontent_tags %} - {% app_reverse "mymodel_detail" "myapp.urls" name1=value1 name2=value2 %} + {% app_reverse "mymodel_detail" "myapp.urls" name1=value1 %} The first argument is a path to a view. The second argument is the URLconf - under which this app is known to the ApplicationContent. The second argument - may also be a request object if you want to reverse an URL belonging to the - current application content. + under which this app is known to the ApplicationContent. The second + argument may also be a request object if you want to reverse an URL + belonging to the current application content. Other arguments are space-separated values that will be filled in place of positional and keyword arguments in the URL. Don't mix positional and @@ -114,7 +116,8 @@ def app_reverse(parser, token): for bit in bits: match = kwarg_re.match(bit) if not match: - raise TemplateSyntaxError("Malformed arguments to app_reverse tag") + raise TemplateSyntaxError( + "Malformed arguments to app_reverse tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 227267e28..f854d8640 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -64,7 +64,8 @@ def feincms_frontend_editing(cms_obj, request): {% feincms_frontend_editing feincms_page request %} """ - if hasattr(request, 'COOKIES') and request.COOKIES.get('frontend_editing') == 'True': + if (hasattr(request, 'COOKIES') + and request.COOKIES.get('frontend_editing') == 'True'): context = template.RequestContext(request, { "feincms_page": cms_obj, }) @@ -73,7 +74,8 @@ def feincms_frontend_editing(cms_obj, request): return u'' -@register.inclusion_tag('admin/feincms/content_type_selection_widget.html', takes_context=True) +@register.inclusion_tag('admin/feincms/content_type_selection_widget.html', + takes_context=True) def show_content_type_selection_widget(context, region): """ {% show_content_type_selection_widget region %} diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 6107a8326..c1f4e2da4 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -80,7 +80,9 @@ def __str__(self): generate = True else: try: - generate = storage.modified_time(miniature) < storage.modified_time(filename) + generate = ( + storage.modified_time(miniature) + < storage.modified_time(filename)) except (NotImplementedError, AttributeError): # storage does NOT support modified_time generate = False @@ -127,7 +129,8 @@ def generate(self, storage, original, size, miniature): class CropscaleThumbnailer(Thumbnailer): - THUMBNAIL_SIZE_RE = re.compile(r'^(?P<w>\d+)x(?P<h>\d+)(-(?P<x>\d+)x(?P<y>\d+))?$') + THUMBNAIL_SIZE_RE = re.compile( + r'^(?P<w>\d+)x(?P<h>\d+)(-(?P<x>\d+)x(?P<y>\d+))?$') MARKER = '_cropscale_' def generate(self, storage, original, size, miniature): diff --git a/feincms/templatetags/fragment_tags.py b/feincms/templatetags/fragment_tags.py index a3a46d156..2234ef2e3 100644 --- a/feincms/templatetags/fragment_tags.py +++ b/feincms/templatetags/fragment_tags.py @@ -43,7 +43,9 @@ def fragment(parser, token): or:: - {% fragment request "title" (prepend|replace|append) %} content ... {% endfragment %} + {% fragment request "title" (prepend|replace|append) %} + content ... + {% endfragment %} """ nodelist = parser.parse(('endfragment'),) diff --git a/feincms/translations.py b/feincms/translations.py index 4bbfe3150..1018c2d4d 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -14,8 +14,8 @@ class NewsTranslation(Translation(News)): body = models.TextField() -Print the titles of all news entries either in the current language (if available) -or in any other language:: +Print the titles of all news entries either in the current language (if +available) or in any other language:: for news in News.objects.all(): print news.translation.title @@ -50,7 +50,8 @@ class _NoTranslation(object): def short_language_code(code=None): """ - Extract the short language code from its argument (or return the default language code). + Extract the short language code from its argument (or return the default + language code). >>> short_language_code('de') 'de' @@ -70,8 +71,9 @@ def short_language_code(code=None): def is_primary_language(language=None): """ - Returns true if current or passed language is the primary language for this site. - (The primary language is defined as the first language in settings.LANGUAGES.) + Returns true if current or passed language is the primary language for this + site. (The primary language is defined as the first language in + settings.LANGUAGES.) """ if not language: @@ -92,7 +94,8 @@ def _transform(qs): instance_dict = {} - # Don't do anything for those who already have a cached translation available + # Don't do anything for those who already have a cached translation + # available for instance in qs: trans = cache.get(instance.get_translation_cache_key(lang_)) if trans: @@ -107,14 +110,18 @@ def _transform(qs): if not instance_dict: return - candidates = list(instance_dict.values())[0].translations.model._default_manager.all() + candidates = list( + instance_dict.values() + )[0].translations.model._default_manager.all() if instance_dict: _process(candidates, instance_dict, lang_, 'iexact') if instance_dict: - _process(candidates, instance_dict, settings.LANGUAGE_CODE, 'istartswith') + _process(candidates, instance_dict, settings.LANGUAGE_CODE, + 'istartswith') if instance_dict: - for candidate in candidates.filter(parent__pk__in=instance_dict.keys()): + for candidate in candidates.filter( + parent__pk__in=instance_dict.keys()): if candidate.parent_id in instance_dict: _found(instance_dict, candidate) @@ -174,7 +181,8 @@ def _get_translation_object(self, queryset, language_code): try: return queryset.filter( Q(language_code__istartswith=settings.LANGUAGE_CODE) - | Q(language_code__istartswith=short_language_code(settings.LANGUAGE_CODE)) + | Q(language_code__istartswith=short_language_code( + settings.LANGUAGE_CODE)) ).order_by('-language_code')[0] except IndexError: try: @@ -183,7 +191,8 @@ def _get_translation_object(self, queryset, language_code): raise queryset.model.DoesNotExist def get_translation_cache_key(self, language_code=None): - """Return the cache key used to cache this object's translations so we can purge on-demand""" + """Return the cache key used to cache this object's translations so we + can purge on-demand""" if not language_code: language_code = translation.get_language() return (('FEINCMS:%d:XLATION:' % getattr(settings, 'SITE_ID', 0)) + @@ -203,7 +212,8 @@ def get_translation(self, language_code=None): if trans is None: try: - trans = self._get_translation_object(self.translations.all(), language_code) + trans = self._get_translation_object( + self.translations.all(), language_code) except ObjectDoesNotExist: trans = _NoTranslation cache.set(key, trans) diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index b0661e10b..545114aa8 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -74,9 +74,13 @@ def shorten_string(str, max_length=50, ellipsis=u' … '): if len(str) >= max_length: first_part = int(max_length * 0.6) next_space = str[first_part:(max_length // 2 - first_part)].find(' ') - if next_space >= 0 and first_part + next_space + len(ellipsis) < max_length: + if (next_space >= 0 + and first_part + next_space + len(ellipsis) < max_length): first_part += next_space - return str[:first_part] + ellipsis + str[-(max_length - first_part - len(ellipsis)):] + return ( + str[:first_part] + + ellipsis + + str[-(max_length - first_part - len(ellipsis)):]) return str @@ -90,7 +94,8 @@ def path_to_cache_key(path, max_length=200, prefix=""): path = iri_to_uri(path) - # logic below borrowed from http://richwklein.com/2009/08/04/improving-django-cache-part-ii/ + # logic below borrowed from + # http://richwklein.com/2009/08/04/improving-django-cache-part-ii/ # via acdha's django-sugar if len(path) > max_length: m = md5() diff --git a/feincms/utils/html/tidy.py b/feincms/utils/html/tidy.py index 81b20e8f8..37b50550b 100644 --- a/feincms/utils/html/tidy.py +++ b/feincms/utils/html/tidy.py @@ -14,7 +14,7 @@ unichr = chr -# Based on http://stackoverflow.com/questions/92438/stripping-non-printable-characters-from-a-string-in-python +# Based on http://stackoverflow.com/questions/92438/ # # We omit chars 9-13 (tab, newline, vertical tab, form feed, return) and 32 # (space) to avoid clogging our reports with warnings about common, @@ -77,7 +77,8 @@ def tidy_html(html): for msg in messages: if not doc_mode and "Warning: missing <!DOCTYPE> declaration" in msg: continue - if not doc_mode and "Warning: inserting missing 'title' element" in msg: + if (not doc_mode + and "Warning: inserting missing 'title' element" in msg): continue if not doc_mode and "Warning: inserting implicit <body>" in msg: continue diff --git a/feincms/utils/managers.py b/feincms/utils/managers.py index dd25e4042..0a7cd727c 100644 --- a/feincms/utils/managers.py +++ b/feincms/utils/managers.py @@ -9,10 +9,11 @@ class ActiveAwareContentManagerMixin(object): should either adopt this mixin or implement a similar interface. """ - # A dict of filters which are used to determine whether a page is active or not. - # Extended for example in the datepublisher extension (date-based publishing and - # un-publishing of pages). This will be set in add_to_active_filters() below, - # so we won't share the same dict for derived managers, do not replace with {} here! + # A dict of filters which are used to determine whether a page is active or + # not. Extended for example in the datepublisher extension (date-based + # publishing and un-publishing of pages). This will be set in + # add_to_active_filters() below, so we won't share the same dict for + # derived managers, do not replace with {} here! active_filters = None @classmethod diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 59f240c63..368e11b93 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -38,7 +38,8 @@ def lookup_tags(item_qs): Winter comes to Ogglesbrook [<sledging>, <snow>, <winter>, <skating>] Summer now [<skating>, <sunny>] -But only executes two SQL queries - one to fetch the items, and one to fetch ALL of the tags for those items. +But only executes two SQL queries - one to fetch the items, and one to fetch +ALL of the tags for those items. Since the transformer function can transform an evaluated QuerySet, it doesn't need to make extra database calls at all - it should work for things @@ -54,8 +55,8 @@ def lookup_tags(item_qs): Copyright (c) 2010, Simon Willison. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index f50c23319..26f4d2838 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -71,10 +71,12 @@ def render(self, context): def do_simple_assignment_node_with_var_and_args_helper(cls): def _func(parser, token): try: - tag_name, of_, in_var_name, as_, var_name, args = token.contents.split() + tag_name, of_, in_var_name, as_, var_name, args =\ + token.contents.split() except ValueError: try: - tag_name, of_, in_var_name, as_, var_name = token.contents.split() + tag_name, of_, in_var_name, as_, var_name =\ + token.contents.split() args = '' except ValueError: raise template.TemplateSyntaxError( @@ -101,6 +103,7 @@ def render(self, context): context[self.var_name] = [] return '' - context[self.var_name] = self.what(instance, _parse_args(self.args, context)) + context[self.var_name] = self.what( + instance, _parse_args(self.args, context)) return '' diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index d5c9bfd45..6c78384a7 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -14,7 +14,8 @@ def page_model(self): if not hasattr(self, '_page_model'): self._page_model = get_model(*self.page_model_path.split('.')) if self._page_model is None: - raise ImportError("Can't import model \"%s\"" % self.page_model_path) + raise ImportError( + "Can't import model \"%s\"" % self.page_model_path) return self._page_model def get_object(self): @@ -32,7 +33,8 @@ def dispatch(self, request, *args, **kwargs): try: request.original_path_info = request.path_info request.path_info = settings.FEINCMS_CMS_404_PAGE - response = super(Handler, self).dispatch(request, *args, **kwargs) + response = super(Handler, self).dispatch( + request, *args, **kwargs) response.status_code = 404 return response except Http404: diff --git a/setup.cfg b/setup.cfg index 5b8d7b9c3..129c4cc68 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [flake8] -exclude=venv,.tox -ignore=E501,E123,E124,E128 +exclude=venv,.tox,build,docs +ignore=E123,E124,E128 [wheel] universal = 1 From 622c7d875eb5f44f18324b1370a26c021543223d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 22 Nov 2013 15:50:20 +0100 Subject: [PATCH 0871/1590] The testsuite was already ugly before --- tests/manage.py | 3 +- tests/testapp/applicationcontent_urls.py | 18 +- tests/testapp/models.py | 10 +- tests/testapp/navigation_extensions.py | 3 +- .../testapp/templates/alias_reverse_test.html | 1 + tests/testapp/templates/fragment.html | 1 + .../testapp/templates/full_reverse_test.html | 1 + tests/testapp/templates/inheritance20.html | 4 + tests/testapp/tests/test_cms.py | 32 +- tests/testapp/tests/test_page.py | 567 +++++++++++++----- tests/testapp/tests/test_stuff.py | 28 +- 11 files changed, 466 insertions(+), 202 deletions(-) create mode 100644 tests/testapp/templates/alias_reverse_test.html create mode 100644 tests/testapp/templates/fragment.html create mode 100644 tests/testapp/templates/full_reverse_test.html create mode 100644 tests/testapp/templates/inheritance20.html diff --git a/tests/manage.py b/tests/manage.py index e20cc5e6d..817e86b82 100755 --- a/tests/manage.py +++ b/tests/manage.py @@ -5,7 +5,8 @@ if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings") - sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + sys.path.insert( + 0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from django.core.management import execute_from_command_line diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index 00757b3bc..bde01dc90 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -2,9 +2,9 @@ This is a dummy module used to test the ApplicationContent """ -from django import template from django.conf.urls import patterns, url from django.http import HttpResponse, HttpResponseRedirect +from django.template.loader import render_to_string from feincms.views.decorators import standalone @@ -18,18 +18,15 @@ def args_test(request, kwarg1, kwarg2): def full_reverse_test(request): - t = template.Template('{% load applicationcontent_tags %}{% load url from future %}home:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" %} args:{% app_reverse "ac_args_test" "testapp.applicationcontent_urls" "xy" "zzy" %} base:{% url "feincms_handler" "test" %} homeas:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" as reversed %}{{ reversed }}') - return t.render(template.Context()) + return render_to_string('full_reverse_test.html', {}) def alias_reverse_test(request): - t = template.Template('{% load applicationcontent_tags %}{% load url from future %}home:{% app_reverse "ac_module_root" "whatever" %} args:{% app_reverse "ac_args_test" "whatever" "xy" "zzy" %} base:{% url "feincms_handler" "test" %}') - return t.render(template.Context()) + return render_to_string('alias_reverse_test.html', {}) def fragment(request): - t = template.Template('{% load applicationcontent_tags %}{% fragment request "something" %}some things{% endfragment %}') - return t.render(template.Context({'request': request})) + return render_to_string('fragment.html', {'request': request}) def redirect(request): @@ -41,12 +38,7 @@ def response(request): def inheritance20(request): - return template.Template(''' - {% extends "base.html" %} - some content outside - {% block content %}a content {{ from_appcontent }}{% endblock %} - {% block sidebar %}b content {{ block.super }}{% block bla %}{% endblock %}{% endblock %} - '''), {'from_appcontent': 42} + return 'inheritance20.html', {'from_appcontent': 42} urlpatterns = patterns('', diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 1f6225dd1..1b3f8a870 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -10,7 +10,8 @@ from feincms.content.image.models import ImageContent from feincms.content.medialibrary.models import MediaFileContent from feincms.content.application.models import ApplicationContent -from feincms.module.page.extensions.navigation import NavigationExtension, PagePretender +from feincms.module.page.extensions.navigation import (NavigationExtension, + PagePretender) from feincms.content.application.models import reverse from mptt.models import MPTTModel @@ -40,7 +41,9 @@ def get_admin_fields(form, *args, **kwargs): label=capfirst(_('exclusive subpages')), required=False, initial=form.instance.parameters.get('exclusive_subpages', False), - help_text=_('Exclude everything other than the application\'s content when rendering subpages.'), + help_text=_( + 'Exclude everything other than the application\'s content' + ' when rendering subpages.'), ), } @@ -77,7 +80,8 @@ def children(self, page, **kwargs): for entry in Entry.objects.all(): yield PagePretender( title=entry.title, - url=reverse('testapp.blog_urls/blog_entry_detail', kwargs={'object_id': entry.id}), + url=reverse('testapp.blog_urls/blog_entry_detail', + kwargs={'object_id': entry.id}), ) Page.register_extensions( diff --git a/tests/testapp/navigation_extensions.py b/tests/testapp/navigation_extensions.py index 0709c2f86..7a34cc893 100644 --- a/tests/testapp/navigation_extensions.py +++ b/tests/testapp/navigation_extensions.py @@ -1,4 +1,5 @@ -from feincms.module.page.extensions.navigation import NavigationExtension, PagePretender +from feincms.module.page.extensions.navigation import (NavigationExtension, + PagePretender) class PassthroughExtension(NavigationExtension): diff --git a/tests/testapp/templates/alias_reverse_test.html b/tests/testapp/templates/alias_reverse_test.html new file mode 100644 index 000000000..6e2203626 --- /dev/null +++ b/tests/testapp/templates/alias_reverse_test.html @@ -0,0 +1 @@ +{% load applicationcontent_tags %}{% load url from future %}home:{% app_reverse "ac_module_root" "whatever" %} args:{% app_reverse "ac_args_test" "whatever" "xy" "zzy" %} base:{% url "feincms_handler" "test" %} diff --git a/tests/testapp/templates/fragment.html b/tests/testapp/templates/fragment.html new file mode 100644 index 000000000..6280945b8 --- /dev/null +++ b/tests/testapp/templates/fragment.html @@ -0,0 +1 @@ +{% load applicationcontent_tags %}{% fragment request "something" %}some things{% endfragment %} diff --git a/tests/testapp/templates/full_reverse_test.html b/tests/testapp/templates/full_reverse_test.html new file mode 100644 index 000000000..ab31b0f10 --- /dev/null +++ b/tests/testapp/templates/full_reverse_test.html @@ -0,0 +1 @@ +{% load applicationcontent_tags %}{% load url from future %}home:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" %} args:{% app_reverse "ac_args_test" "testapp.applicationcontent_urls" "xy" "zzy" %} base:{% url "feincms_handler" "test" %} homeas:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" as reversed %}{{ reversed }} diff --git a/tests/testapp/templates/inheritance20.html b/tests/testapp/templates/inheritance20.html new file mode 100644 index 000000000..00e2b8705 --- /dev/null +++ b/tests/testapp/templates/inheritance20.html @@ -0,0 +1,4 @@ +{% extends "base.html" %} +some content outside +{% block content %}a content {{ from_appcontent }}{% endblock %} +{% block sidebar %}b content {{ block.super }}{% block bla %}{% endblock %}{% endblock %} diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 17685740a..6a6e5f5f9 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -37,14 +37,19 @@ def test_01_simple_content_type_creation(self): ExampleCMSBase.create_content_type(RawContent) ExampleCMSBase.create_content_type(RichTextContent) - # test creating a cotent with arguments, but no initialize_type classmethod - ExampleCMSBase.create_content_type(VideoContent, arbitrary_arg='arbitrary_value') + # test creating a cotent with arguments, but no initialize_type + # classmethod + ExampleCMSBase.create_content_type(VideoContent, + arbitrary_arg='arbitrary_value') - # content_type_for should return None if it does not have a subclass registered + # content_type_for should return None if it does not have a subclass + # registered self.assertEqual(ExampleCMSBase.content_type_for(Empty), None) - self.assertTrue('filecontent' not in dict(ExampleCMSBase.template.regions[0].content_types).keys()) - self.assertTrue('filecontent' in dict(ExampleCMSBase.template.regions[1].content_types).keys()) + self.assertTrue('filecontent' not in dict( + ExampleCMSBase.template.regions[0].content_types).keys()) + self.assertTrue('filecontent' in dict( + ExampleCMSBase.template.regions[1].content_types).keys()) def test_02_rsscontent_creation(self): # this test resides in its own method because the required feedparser @@ -84,10 +89,11 @@ def test_04_mediafilecontent_creation(self): # no TYPE_CHOICES, should raise self.assertRaises(ImproperlyConfigured, - lambda: ExampleCMSBase.create_content_type(MediaFileContent)) + lambda: ExampleCMSBase.create_content_type(MediaFileContent)) def test_05_non_abstract_content_type(self): - # Should not be able to create a content type from a non-abstract base type + # Should not be able to create a content type from a non-abstract base + # type class TestContentType(models.Model): pass @@ -127,9 +133,11 @@ def test_08_creating_two_content_types_in_same_application(self): ct = ExampleCMSBase.content_type_for(RawContent) self.assertEqual(ct._meta.db_table, 'tests_examplecmsbase_rawcontent') - ExampleCMSBase2.create_content_type(RawContent, class_name='RawContent2') + ExampleCMSBase2.create_content_type(RawContent, + class_name='RawContent2') ct2 = ExampleCMSBase2.content_type_for(RawContent) - self.assertEqual(ct2._meta.db_table, 'tests_examplecmsbase2_rawcontent2') + self.assertEqual(ct2._meta.db_table, + 'tests_examplecmsbase2_rawcontent2') def test_09_related_objects_cache(self): """ @@ -141,7 +149,8 @@ def test_09_related_objects_cache(self): related models have been defined. """ class Attachment(models.Model): - base = models.ForeignKey(ExampleCMSBase, related_name='test_related_name') + base = models.ForeignKey(ExampleCMSBase, + related_name='test_related_name') # See issue #323 on Github. ExampleCMSBase._meta._fill_related_objects_cache() @@ -154,7 +163,8 @@ class Attachment(models.Model): #self.assertFalse(hasattr(Attachment, 'anycontents')) class AnyContent(models.Model): - attachment = models.ForeignKey(Attachment, related_name='anycontents') + attachment = models.ForeignKey(Attachment, + related_name='anycontents') class Meta: abstract = True diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index e2eb36805..e69f0dc91 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -45,7 +45,8 @@ # ------------------------------------------------------------------------ class PagesTestCase(TestCase): def setUp(self): - u = User(username='test', is_active=True, is_staff=True, is_superuser=True) + u = User(username='test', is_active=True, is_staff=True, + is_superuser=True) u.set_password('test') u.save() @@ -72,7 +73,8 @@ def setUp(self): def login(self): self.assertTrue(self.client.login(username='test', password='test')) - def create_page_through_admin(self, title='Test page', parent='', **kwargs): + def create_page_through_admin(self, title='Test page', parent='', + **kwargs): dic = { 'title': title, 'slug': kwargs.get('slug', slugify(title)), @@ -150,27 +152,37 @@ def is_published(self, url, should_be=True): def test_01_tree_editor(self): self.login() - self.assertEqual(self.client.get('/admin/page/page/').status_code, 200) + self.assertEqual( + self.client.get('/admin/page/page/').status_code, 200) - self.assertRedirects(self.client.get('/admin/page/page/?anything=anything'), - '/admin/page/page/?e=1') + self.assertRedirects( + self.client.get('/admin/page/page/?anything=anything'), + '/admin/page/page/?e=1') def test_02_add_page(self): self.login() - self.assertRedirects(self.create_page_through_admin(title='Test page ' * 10, slug='test-page'), - '/admin/page/page/') + self.assertRedirects( + self.create_page_through_admin( + title='Test page ' * 10, + slug='test-page'), + '/admin/page/page/') self.assertEqual(Page.objects.count(), 1) self.assertContains(self.client.get('/admin/page/page/'), u'…') def test_03_item_editor(self): self.login() - self.assertRedirects(self.create_page_through_admin(_continue=1), '/admin/page/page/1/') - self.assertEqual(self.client.get('/admin/page/page/1/').status_code, 200) + self.assertRedirects( + self.create_page_through_admin(_continue=1), + '/admin/page/page/1/') + self.assertEqual( + self.client.get('/admin/page/page/1/').status_code, 200) self.is_published('/admin/page/page/42/', should_be=False) def test_03_add_another(self): self.login() - self.assertRedirects(self.create_page_through_admin(_addanother=1), '/admin/page/page/add/') + self.assertRedirects( + self.create_page_through_admin(_addanother=1), + '/admin/page/page/add/') def test_04_add_child(self): response = self.create_default_page_set_through_admin() @@ -178,7 +190,8 @@ def test_04_add_child(self): self.assertEqual(Page.objects.count(), 2) page = Page.objects.get(pk=2) - self.assertEqual(page.get_absolute_url(), '/test-page/test-child-page/') + self.assertEqual( + page.get_absolute_url(), '/test-page/test-child-page/') page.active = True page.in_navigation = True @@ -202,14 +215,14 @@ def test_05_override_url(self): page.save() page2 = Page.objects.get(pk=2) - self.assertEqual(page2.get_absolute_url(), '/something/test-child-page/') + self.assertEqual( + page2.get_absolute_url(), '/something/test-child-page/') page.override_url = '/' page.save() page2 = Page.objects.get(pk=2) self.assertEqual(page2.get_absolute_url(), '/test-child-page/') - # This goes through feincms.views.base.handler instead of the applicationcontent handler self.is_published('/', False) page.active = True page.template_key = 'theother' @@ -226,7 +239,8 @@ def test_06_tree_editor_save(self): page4 = Page.objects.create(title='page4', slug='page4', parent=page1) page5 = Page.objects.create(title='page5', slug='page5', parent=None) - self.assertEqual(page3.get_absolute_url(), '/test-page/test-child-page/page3/') + self.assertEqual( + page3.get_absolute_url(), '/test-page/test-child-page/page3/') self.assertEqual(page4.get_absolute_url(), '/test-page/page4/') self.assertEqual(page5.get_absolute_url(), '/page5/') @@ -270,7 +284,8 @@ def test_07_tree_editor_toggle_boolean(self): '__cmd': 'toggle_boolean', 'item_id': 1, 'attr': 'notexists', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), HttpResponseBadRequest)) + }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), + HttpResponseBadRequest)) def test_07_tree_editor_invalid_ajax(self): self.login() @@ -384,9 +399,12 @@ def test_09_pagecontent(self): # other content methods self.assertEqual(len(page2.content.all_of_type(RawContent)), 1) - self.assertEqual(page2.content.main[0].__class__.__name__, 'RawContent') - self.assertEqual(force_text(page2.content.main[0]), - u'RawContent<pk=1, parent=Page<pk=1, Test page>, region=main, ordering=0>') + self.assertEqual( + page2.content.main[0].__class__.__name__, 'RawContent') + self.assertEqual( + force_text(page2.content.main[0]), + u'RawContent<pk=1, parent=Page<pk=1, Test page>, region=main,' + u' ordering=0>') self.assertEqual(len(page2.content.main), 1) self.assertEqual(len(page2.content.sidebar), 0) @@ -430,32 +448,43 @@ def test_10_mediafile_and_imagecontent(self): mf = page.content.main[1].mediafile self.assertEqual(mf.translation.caption, 'something') - self.assertEqual(mf.translation.short_language_code(), short_language_code()) + self.assertEqual( + mf.translation.short_language_code(), short_language_code()) self.assertNotEqual(mf.get_absolute_url(), '') self.assertEqual(force_text(mf), 'something') self.assertTrue(mf.type == 'image') self.assertEqual(MediaFile.objects.only_language('de').count(), 0) self.assertEqual(MediaFile.objects.only_language('en').count(), 0) - self.assertEqual(MediaFile.objects.only_language('%s-ha' % short_language_code()).count(), - 1) + self.assertEqual( + MediaFile.objects.only_language( + '%s-ha' % short_language_code()).count(), + 1) - self.assertTrue('%s-ha' % short_language_code() in mf.available_translations) + self.assertTrue( + '%s-ha' % short_language_code() in mf.available_translations) # this should not raise self.client.get('/admin/page/page/1/') - #self.assertTrue('alt="something"' in page.content.main[1].render()) Since it isn't an image + # self.assertTrue('alt="something"' in page.content.main[1].render()) + # Since it isn't an image - page.imagecontent_set.create(image='somefile.jpg', region='main', position='default', ordering=2) - page.filecontent_set.create(file='somefile.jpg', title='thetitle', region='main', ordering=3) + page.imagecontent_set.create( + image='somefile.jpg', region='main', position='default', + ordering=2) + page.filecontent_set.create( + file='somefile.jpg', title='thetitle', region='main', ordering=3) # Reload page, reset _ct_inventory page = Page.objects.get(pk=page.pk) page._ct_inventory = None self.assertTrue('somefile.jpg' in page.content.main[2].render()) - self.assertTrue(re.search('<a .*href="somefile\.jpg">.*thetitle.*</a>', page.content.main[3].render(), re.MULTILINE + re.DOTALL) is not None) + self.assertTrue(re.search( + '<a .*href="somefile\.jpg">.*thetitle.*</a>', + page.content.main[3].render(), + re.MULTILINE + re.DOTALL) is not None) page.mediafilecontent_set.update(mediafile=3) # this should not raise @@ -464,8 +493,9 @@ def test_10_mediafile_and_imagecontent(self): field = MediaFile._meta.get_field('file') old = (field.upload_to, field.storage, field.generate_filename) from django.core.files.storage import FileSystemStorage - MediaFile.reconfigure(upload_to=lambda: 'anywhere', - storage=FileSystemStorage(location='/wha/', base_url='/whe/')) + MediaFile.reconfigure( + upload_to=lambda: 'anywhere', + storage=FileSystemStorage(location='/wha/', base_url='/whe/')) mediafile = MediaFile.objects.get(pk=1) self.assertEqual(mediafile.file.url, '/whe/somefile.jpg') @@ -549,11 +579,14 @@ def test_13_inheritance_and_ct_tracker(self): page2.content_proxy_class = ContentProxy if hasattr(self, 'assertNumQueries'): - # 4 queries: Two to get the content types of page and page2, one to - # fetch all ancestor PKs of page2 and one to materialize the RawContent - # instances belonging to page's sidebar and page2's main. - self.assertNumQueries(4, lambda: [page2.content.main, page2.content.sidebar]) - self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) + # 4 queries: Two to get the content types of page and page2, one to + # fetch all ancestor PKs of page2 and one to materialize the + # RawContent instances belonging to page's sidebar and page2's + # main. + self.assertNumQueries( + 4, lambda: [page2.content.main, page2.content.sidebar]) + self.assertNumQueries( + 0, lambda: page2.content.sidebar[0].render()) self.assertEqual(u''.join(c.render() for c in page2.content.main), 'Something elseWhatever') @@ -568,14 +601,16 @@ def test_13_inheritance_and_ct_tracker(self): if hasattr(self, 'assertNumQueries'): # 5 queries: Two to get the content types of page and page2, one to - # fetch all ancestor PKs of page2 and one to materialize the RawContent - # instances belonging to page's sidebar and page2's main and a few - # queries to update the pages _ct_inventory attributes: + # fetch all ancestor PKs of page2 and one to materialize the + # RawContent instances belonging to page's sidebar and page2's main + # and a few queries to update the pages _ct_inventory attributes: # - one update to update page2 - # - one update to clobber the _ct_inventory attribute of all descendants - # of page2 - self.assertNumQueries(5, lambda: [page2.content.main, page2.content.sidebar]) - self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) + # - one update to clobber the _ct_inventory attribute of all + # descendants of page2 + self.assertNumQueries( + 5, lambda: [page2.content.main, page2.content.sidebar]) + self.assertNumQueries( + 0, lambda: page2.content.sidebar[0].render()) self.assertEqual(page2.content.sidebar[0].render(), 'Something') @@ -583,7 +618,8 @@ def test_13_inheritance_and_ct_tracker(self): page2 = Page.objects.get(pk=2) if hasattr(self, 'assertNumQueries'): - self.assertNumQueries(1, lambda: [page2.content.main, page2.content.sidebar]) + self.assertNumQueries( + 1, lambda: [page2.content.main, page2.content.sidebar]) self.assertNotEqual(page2._ct_inventory, {}) @@ -591,7 +627,8 @@ def test_14_richtext(self): # only create the content type to test the item editor # customization hooks tmp = Page._feincms_content_types[:] - type = Page.create_content_type(RichTextContent, regions=('notexists',)) + type = Page.create_content_type( + RichTextContent, regions=('notexists',)) Page._feincms_content_types = tmp from django.utils.safestring import SafeData @@ -609,7 +646,9 @@ def test_15_frontend_editing(self): self.is_published('/admin/page/page/10|rawcontent|1/', should_be=False) self.is_published('/admin/page/page/1|rawcontent|10/', should_be=False) - self.assertEqual(self.client.get('/admin/page/page/1|rawcontent|1/').status_code, 200) + self.assertEqual( + self.client.get('/admin/page/page/1|rawcontent|1/').status_code, + 200) self.assertEqual(self.client.post('/admin/page/page/1|rawcontent|1/', { 'rawcontent-text': 'blablabla', }).status_code, 200) @@ -697,68 +736,148 @@ def test_17_page_template_tags(self): context = template.Context({'feincms_page': page2, 'page3': page3}) - t = template.Template('{% load feincms_page_tags %}{% feincms_parentlink of feincms_page level=1 %}') + t = template.Template( + '{% load feincms_page_tags %}{% feincms_parentlink of feincms_page' + ' level=1 %}') self.assertEqual(t.render(context), '/test-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for feincms_page as links %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/,de:/test-page/test-child-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for page3 as links %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/test-child-page/page3/,de:None') + t = template.Template( + '{% load feincms_page_tags %}{% feincms_languagelinks for' + ' feincms_page as links %}{% for key, name, link in links %}' + '{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}' + '{% endfor %}') + self.assertEqual( + t.render(context), + 'en:/test-page/,de:/test-page/test-child-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for page3 as links existing %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/test-child-page/page3/') + t = template.Template( + '{% load feincms_page_tags %}{% feincms_languagelinks for page3' + ' as links %}{% for key, name, link in links %}{{ key }}:' + '{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual( + t.render(context), + 'en:/test-page/test-child-page/page3/,de:None') - t = template.Template('{% load feincms_page_tags %}{% feincms_languagelinks for feincms_page as links excludecurrent=1 %}{% for key, name, link in links %}{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template( + '{% load feincms_page_tags %}{% feincms_languagelinks for page3' + ' as links existing %}{% for key, name, link in links %}{{ key }}:' + '{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual( + t.render(context), + 'en:/test-page/test-child-page/page3/') + + t = template.Template( + '{% load feincms_page_tags %}{% feincms_languagelinks for' + ' feincms_page as links excludecurrent=1 %}' + '{% for key, name, link in links %}{{ key }}:{{ link }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), 'en:/test-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=1 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '') - # XXX should the other template tags not respect the in_navigation setting too? + # XXX should the other template tags not respect the in_navigation + # setting too? page1.active = True page1.in_navigation = True page1.save() self.assertEqual(t.render(context), '/test-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '/test-page/test-child-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_nav request level=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav request level=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') + from django.http import HttpRequest request = HttpRequest() request.path = '/test-page/' - self.assertEqual(t.render(template.Context({'request': request})), '/test-page/test-child-page/') + self.assertEqual( + t.render(template.Context({'request': request})), + '/test-page/test-child-page/') - t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=99 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=99 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') self.assertEqual(t.render(context), '') - t = template.Template('{% load feincms_page_tags %}{% feincms_breadcrumbs feincms_page %}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_breadcrumbs feincms_page %}') rendered = t.render(context) self.assertTrue("Test child page" in rendered) - self.assertTrue('href="/test-page/">Test page</a>' in rendered, msg="The parent page should be a breadcrumb link") - self.assertTrue('href="/test-page/test-child-page/"' not in rendered, msg="The current page should not be a link in the breadcrumbs") - - t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=2 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/test-child-page/,/test-page/test-child-page/page3/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=3 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/,/test-page/test-child-page/,/test-page/test-child-page/page3/') - - t = template.Template('{% load feincms_page_tags %}{% feincms_nav feincms_page level=3 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/test-child-page/page3/') + self.assertTrue('href="/test-page/">Test page</a>' in rendered, + msg="The parent page should be a breadcrumb link") + self.assertTrue('href="/test-page/test-child-page/"' not in rendered, + msg="The current page should not be a link in the breadcrumbs") + + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=2 depth=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual( + t.render(context), + '/test-page/test-child-page/,/test-page/test-child-page/page3/') + + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=1 depth=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual( + t.render(context), + '/test-page/,/test-page/test-child-page/') + + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=1 depth=3 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual( + t.render(context), + '/test-page/,/test-page/test-child-page/,/test-page/test-child' + '-page/page3/') + + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=3 depth=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}') + self.assertEqual( + t.render(context), '/test-page/test-child-page/page3/') - t = template.Template('{% load feincms_page_tags %}{% if feincms_page|is_parent_of:page3 %}yes{% endif %}|{% if page3|is_parent_of:feincms_page %}yes{% endif %}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% if feincms_page|is_parent_of:page3 %}yes{% endif %}|' + '{% if page3|is_parent_of:feincms_page %}yes{% endif %}') self.assertEqual(t.render(context), 'yes|') - t = template.Template('{% load feincms_page_tags %}{% if feincms_page|is_equal_or_parent_of:page3 %}yes{% endif %}|{% if page3|is_equal_or_parent_of:feincms_page %}yes{% endif %}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% if feincms_page|is_equal_or_parent_of:page3 %}yes{% endif %}|' + '{% if page3|is_equal_or_parent_of:feincms_page %}yes{% endif %}') self.assertEqual(t.render(context), 'yes|') - t = template.Template('{% load feincms_page_tags %}{% feincms_translatedpage for feincms_page as t1 language=de %}{% feincms_translatedpage for feincms_page as t2 %}{{ t1.id }}|{{ t2.id }}') + t = template.Template( + '{% load feincms_page_tags %}' + '{% feincms_translatedpage for feincms_page as t1 language=de %}' + '{% feincms_translatedpage for feincms_page as t2 %}' + '{{ t1.id }}|{{ t2.id }}') self.assertEqual(t.render(context), '2|1') def test_17_feincms_nav(self): @@ -820,27 +939,49 @@ def test_17_feincms_nav(self): tests = [ ( {'feincms_page': Page.objects.get(pk=1)}, - '{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=1 depth=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/' + ',/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-' + '3/page-31/,/page-3/page-32/,/page-3/page-33/', ), ( {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}{% feincms_nav feincms_page level=2 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-332/', + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=2 depth=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/' + 'page-33/page-331/,/page-3/page-33/page-332/', ), ( {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}{% feincms_nav feincms_page level=2 depth=3 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/page-33/page-331/,/page-3/page-33/page-331/page-3311/,/page-3/page-33/page-332/', + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=2 depth=3 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/' + 'page-33/page-331/,/page-3/page-33/page-331/page-3311/,/page' + '-3/page-33/page-332/', ), ( {'feincms_page': Page.objects.get(pk=19)}, - '{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=2 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-3/page-31/,/page-3/page-32/,/page-3/page-33/', + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=1 depth=2 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}', + '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13' + '/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/pag' + 'e-3/page-31/,/page-3/page-32/,/page-3/page-33/', ), ( {'feincms_page': Page.objects.get(pk=1)}, - '{% load feincms_page_tags %}{% feincms_nav feincms_page level=3 depth=1 as nav %}{% for p in nav %}{{ p.get_absolute_url }}{% if not forloop.last %},{% endif %}{% endfor %}', + '{% load feincms_page_tags %}' + '{% feincms_nav feincms_page level=3 depth=1 as nav %}' + '{% for p in nav %}{{ p.get_absolute_url }}' + '{% if not forloop.last %},{% endif %}{% endfor %}', '', ), ] @@ -855,7 +996,8 @@ def test_17_feincms_nav(self): # which does only have direct children, because it does not collect # pages further down the tree. page = Page.objects.get(pk=8) - page.navigation_extension = 'testapp.navigation_extensions.PassthroughExtension' + page.navigation_extension =\ + 'testapp.navigation_extensions.PassthroughExtension' page.save() for c, t, r in tests: @@ -865,27 +1007,53 @@ def test_17_feincms_nav(self): # Now check that disabling a page also disables it in Navigation: p = Page.objects.get(pk=15) - tmpl = '{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=3 as nav %}{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %}' - - data = template.Template(tmpl).render(template.Context({'feincms_page': p})), - self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") + tmpl = '''{% load feincms_page_tags %} +{% feincms_nav feincms_page level=1 depth=3 as nav %} +{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %} +''' + + data = template.Template(tmpl).render( + template.Context({'feincms_page': p}) + ).strip(), + self.assertEqual( + data, + (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), + "Original navigation") p.active = False p.save() - data = template.Template(tmpl).render(template.Context({'feincms_page': p})), - self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") + data = template.Template(tmpl).render( + template.Context({'feincms_page': p}) + ).strip(), + self.assertEqual( + data, + (u'1,2,3,4,6,7,8,10,11,12,13,14',), + "Navigation after disabling intermediate page") # Same test with feincms_nav - tmpl = '{% load feincms_page_tags %}{% feincms_nav feincms_page level=1 depth=3 as nav %}{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %}' - - data = template.Template(tmpl).render(template.Context({'feincms_page': p})), - self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") + tmpl = '''{% load feincms_page_tags %} +{% feincms_nav feincms_page level=1 depth=3 as nav %} +{% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %} +''' + + data = template.Template(tmpl).render( + template.Context({'feincms_page': p}) + ).strip(), + self.assertEqual( + data, + (u'1,2,3,4,6,7,8,10,11,12,13,14',), + "Navigation after disabling intermediate page") p.active = True p.save() - data = template.Template(tmpl).render(template.Context({'feincms_page': p})), - self.assertEqual(data, (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") + data = template.Template(tmpl).render( + template.Context({'feincms_page': p}) + ).strip(), + self.assertEqual( + data, + (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), + "Original navigation") def test_18_default_render_method(self): """ @@ -900,7 +1068,8 @@ class Meta: def render_main(self): return u'Hello' - # do not register this model in the internal FeinCMS bookkeeping structures + # do not register this model in the internal FeinCMS bookkeeping + # structures tmp = Page._feincms_content_types[:] type = Page.create_content_type(Something, regions=('notexists',)) Page._feincms_content_types = tmp @@ -974,7 +1143,8 @@ def test_19_page_manager(self): feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True self.assertEqual(self.client.get(request.path).status_code, 200) - self.assertEqual(page, Page.objects.for_request(request, best_match=True)) + self.assertEqual( + page, Page.objects.for_request(request, best_match=True)) feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old @@ -1001,7 +1171,8 @@ def test_20_redirects(self): # page2 has been modified too, but its URL should not have changed try: - self.assertRedirects(self.client.get('/blablabla/'), page1.get_absolute_url()) + self.assertRedirects( + self.client.get('/blablabla/'), page1.get_absolute_url()) except TemplateDoesNotExist as e: # catch the error from rendering page1 if e.args != ('feincms_base.html',): @@ -1024,8 +1195,9 @@ def test_22_contactform(self): page.template_key = 'theother' page.save() - page.contactformcontent_set.create(email='mail@example.com', subject='bla', - region='main', ordering=0) + page.contactformcontent_set.create( + email='mail@example.com', subject='bla', + region='main', ordering=0) request = Empty() request.method = 'GET' @@ -1046,7 +1218,8 @@ def test_22_contactform(self): }) self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].subject, 'This is a test. Please calm down') + self.assertEqual( + mail.outbox[0].subject, 'This is a test. Please calm down') def test_23_navigation_extension(self): self.create_default_page_set() @@ -1055,7 +1228,8 @@ def test_23_navigation_extension(self): self.assertEqual(len(page.extended_navigation()), 0) - page.navigation_extension = 'testapp.navigation_extensions.PassthroughExtension' + page.navigation_extension =\ + 'testapp.navigation_extensions.PassthroughExtension' page2 = Page.objects.get(pk=2) page2.active = True @@ -1064,13 +1238,16 @@ def test_23_navigation_extension(self): self.assertEqual(list(page.extended_navigation()), [page2]) - page.navigation_extension = 'testapp.navigation_extensions.ThisExtensionDoesNotExist' + page.navigation_extension =\ + 'testapp.navigation_extensions.ThisExtensionDoesNotExist' self.assertEqual(len(page.extended_navigation()), 1) - page.navigation_extension = 'testapp.navigation_extensions.PretenderExtension' + page.navigation_extension =\ + 'testapp.navigation_extensions.PretenderExtension' - self.assertEqual(page.extended_navigation()[0].get_absolute_url(), '/asdsa/') + self.assertEqual( + page.extended_navigation()[0].get_absolute_url(), '/asdsa/') def test_24_admin_redirects(self): self.create_default_page_set() @@ -1098,51 +1275,66 @@ def test_25_applicationcontent(self): page.template_key = 'theother' page.save() - # Should not be published because the page has no application contents and should - # therefore not catch anything below it. + # Should not be published because the page has no application contents + # and should therefore not catch anything below it. self.is_published(page1.get_absolute_url() + 'anything/', False) page.applicationcontent_set.create( region='main', ordering=0, urlconf_path='testapp.applicationcontent_urls') - self.assertContains(self.client.get(page.get_absolute_url()), - 'module_root') - self.assertContains(self.client.get(page.get_absolute_url() + 'args_test/abc/def/'), - 'abc-def') - self.assertContains(self.client.get(page.get_absolute_url() + 'kwargs_test/abc/def/'), - 'def-abc') - - response = self.client.get(page.get_absolute_url() + 'full_reverse_test/') + self.assertContains( + self.client.get(page.get_absolute_url()), + 'module_root') + self.assertContains( + self.client.get(page.get_absolute_url() + 'args_test/abc/def/'), + 'abc-def') + self.assertContains( + self.client.get(page.get_absolute_url() + 'kwargs_test/abc/def/'), + 'def-abc') + + response = self.client.get( + page.get_absolute_url() + 'full_reverse_test/') self.assertContains(response, 'home:/test-page/test-child-page/') - self.assertContains(response, 'args:/test-page/test-child-page/args_test/xy/zzy/') + self.assertContains(response, + 'args:/test-page/test-child-page/args_test/xy/zzy/') self.assertContains(response, 'base:/test/') self.assertContains(response, 'homeas:/test-page/test-child-page/') - self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), + self.assertEqual( + app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), '/test-page/test-child-page/') if hasattr(self, 'assertNumQueries'): self.assertNumQueries(0, - lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) + lambda: app_reverse( + 'ac_module_root', 'testapp.applicationcontent_urls')) cycle_app_reverse_cache() self.assertNumQueries(1, - lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) + lambda: app_reverse( + 'ac_module_root', 'testapp.applicationcontent_urls')) self.assertNumQueries(0, - lambda: app_reverse('ac_module_root', 'testapp.applicationcontent_urls')) + lambda: app_reverse( + 'ac_module_root', 'testapp.applicationcontent_urls')) # This should not raise - self.assertEqual(self.client.get(page.get_absolute_url() + 'notexists/').status_code, 404) + self.assertEqual( + self.client.get( + page.get_absolute_url() + 'notexists/' + ).status_code, 404) - self.assertContains(self.client.get(page.get_absolute_url() + 'fragment/'), - '<span id="something">some things</span>') + self.assertContains( + self.client.get(page.get_absolute_url() + 'fragment/'), + '<span id="something">some things</span>') - self.assertRedirects(self.client.get(page.get_absolute_url() + 'redirect/'), - page.get_absolute_url()) + self.assertRedirects( + self.client.get(page.get_absolute_url() + 'redirect/'), + page.get_absolute_url()) - self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), + self.assertEqual( + app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), page.get_absolute_url()) response = self.client.get(page.get_absolute_url() + 'response/') @@ -1154,7 +1346,8 @@ def test_25_applicationcontent(self): self.assertEqual( self.client.get(page.get_absolute_url() + 'response/', HTTP_X_REQUESTED_WITH='XMLHttpRequest').content, - self.client.get(page.get_absolute_url() + 'response_decorated/').content) + self.client.get( + page.get_absolute_url() + 'response_decorated/').content) # Test reversing of URLs (with overridden urls too) page.applicationcontent_set.create( @@ -1166,20 +1359,31 @@ def test_25_applicationcontent(self): ordering=0, urlconf_path='whatever') - response = self.client.get(page.get_absolute_url() + 'alias_reverse_test/') + response = self.client.get( + page.get_absolute_url() + 'alias_reverse_test/') self.assertContains(response, 'home:/test-page/') self.assertContains(response, 'args:/test-page/args_test/xy/zzy/') self.assertContains(response, 'base:/test/') - self.assertEqual(app_reverse('blog_entry_list', 'testapp.blog_urls'), '/test-page/test-child-page/') - self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), + self.assertEqual( + app_reverse('blog_entry_list', 'testapp.blog_urls'), + '/test-page/test-child-page/') + self.assertEqual( + app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), '/test-page/test-child-page/') - self.assertEqual(app_reverse('ac_module_root', 'whatever'), '/test-page/') + self.assertEqual( + app_reverse('ac_module_root', 'whatever'), + '/test-page/') - page.applicationcontent_set.get(urlconf_path='testapp.applicationcontent_urls').delete() + page.applicationcontent_set.get( + urlconf_path='testapp.applicationcontent_urls').delete() - self.assertEqual(app_reverse('blog_entry_list', 'testapp.blog_urls'), '/test-page/test-child-page/') - self.assertEqual(app_reverse('ac_module_root', 'whatever'), '/test-page/') + self.assertEqual( + app_reverse('blog_entry_list', 'testapp.blog_urls'), + '/test-page/test-child-page/') + self.assertEqual( + app_reverse('ac_module_root', 'whatever'), + '/test-page/') # Ensure ApplicationContent's admin_fields support works properly self.login() @@ -1190,9 +1394,15 @@ def test_26_page_form_initial(self): self.create_default_page_set() self.login() - self.assertEqual(self.client.get('/admin/page/page/add/?translation_of=1&lang=de').status_code, 200) - self.assertEqual(self.client.get('/admin/page/page/add/?parent=1').status_code, 200) - self.assertEqual(self.client.get('/admin/page/page/add/?parent=2').status_code, 200) + self.assertEqual(self.client.get( + '/admin/page/page/add/?translation_of=1&lang=de' + ).status_code, 200) + self.assertEqual(self.client.get( + '/admin/page/page/add/?parent=1' + ).status_code, 200) + self.assertEqual(self.client.get( + '/admin/page/page/add/?parent=2' + ).status_code, 200) def test_27_cached_url_clash(self): self.create_default_page_set() @@ -1205,7 +1415,9 @@ def test_27_cached_url_clash(self): page1.save() self.login() - self.assertContains(self.create_page_through_admincontent(page2, active=True, override_url='/'), + self.assertContains( + self.create_page_through_admincontent( + page2, active=True, override_url='/'), 'already taken by') def test_28_applicationcontent_reverse(self): @@ -1223,15 +1435,18 @@ def test_28_applicationcontent_reverse(self): urlconf_path='testapp.applicationcontent_urls') # test app_reverse - self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - page.get_absolute_url()) + self.assertEqual( + app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), + page.get_absolute_url()) # when specific applicationcontent exists more then once reverse should # return the URL of the first (ordered by primary key) page. self.login() - self.create_page_through_admin(title='Home DE', language='de', active=True) + self.create_page_through_admin( + title='Home DE', language='de', active=True) page_de = Page.objects.get(title='Home DE') - self.create_page_through_admin(title='Child 1 DE', language='de', parent=page_de.id, active=True) + self.create_page_through_admin( + title='Child 1 DE', language='de', parent=page_de.id, active=True) page_de_1 = Page.objects.get(title='Child 1 DE') page_de_1.applicationcontent_set.create( region='main', ordering=0, @@ -1240,17 +1455,21 @@ def test_28_applicationcontent_reverse(self): page.active = False page.save() - settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), 'templates'),) + settings.TEMPLATE_DIRS = ( + os.path.join(os.path.dirname(__file__), 'templates'), + ) self.client.get(page_de_1.get_absolute_url()) - self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - page_de_1.get_absolute_url()) + self.assertEqual( + app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), + page_de_1.get_absolute_url()) page.active = True page.save() self.client.get(page1.get_absolute_url()) - self.assertEqual(app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - page.get_absolute_url()) + self.assertEqual( + app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), + page.get_absolute_url()) def test_29_medialibrary_admin(self): self.create_default_page_set() @@ -1265,7 +1484,9 @@ def test_29_medialibrary_admin(self): type='default', ordering=1) - self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), 'somefile.jpg') + self.assertContains( + self.client.get('/admin/medialibrary/mediafile/'), + 'somefile.jpg') import zipfile zf = zipfile.ZipFile('test.zip', 'w') @@ -1273,22 +1494,26 @@ def test_29_medialibrary_admin(self): zf.writestr('test%d.jpg' % i, 'test%d' % i) zf.close() - self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/mediafile-bulk-upload/', { - 'data': open('test.zip', 'rb'), - }), '/admin/medialibrary/mediafile/') + response = self.client.post( + '/admin/medialibrary/mediafile/mediafile-bulk-upload/', { + 'data': open('test.zip', 'rb'), + }) + self.assertRedirects(response, '/admin/medialibrary/mediafile/') - self.assertEqual(MediaFile.objects.count(), 11, "Upload of media files with ZIP does not work") + self.assertEqual(MediaFile.objects.count(), 11, + "Upload of media files with ZIP does not work") dn = os.path.dirname path = os.path.join(dn(dn(dn(dn(__file__)))), 'docs', 'images', 'tree_editor.png') - self.assertRedirects(self.client.post('/admin/medialibrary/mediafile/add/', { + response = self.client.post('/admin/medialibrary/mediafile/add/', { 'file': open(path, 'rb'), 'translations-TOTAL_FORMS': 0, 'translations-INITIAL_FORMS': 0, 'translations-MAX_NUM_FORMS': 10, - }), '/admin/medialibrary/mediafile/') + }) + self.assertRedirects(response, '/admin/medialibrary/mediafile/') self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), '100x100.png" alt="" />') @@ -1314,7 +1539,8 @@ def test_30_context_processors(self): def test_31_sites_framework_associating_with_single_site(self): self.login() site_2 = Site.objects.create(name='site 2', domain='2.example.com') - self.create_page_through_admin('site 1 homepage', override_url='/', active=True) + self.create_page_through_admin( + 'site 1 homepage', override_url='/', active=True) self.create_page_through_admin('site 2 homepage', override_url='/', site=site_2.id, active=True) self.assertEqual(Page.objects.count(), 2) @@ -1332,8 +1558,8 @@ def test_32_applicationcontent_inheritance20(self): page.template_key = 'theother' page.save() - # Should not be published because the page has no application contents and should - # therefore not catch anything below it. + # Should not be published because the page has no application contents + # and should therefore not catch anything below it. self.is_published(page1.get_absolute_url() + 'anything/', False) page.applicationcontent_set.create( @@ -1365,8 +1591,13 @@ def test_33_preview(self): text='Example content') self.login() - self.assertEqual(self.client.get(page.get_absolute_url()).status_code, 404) - self.assertContains(self.client.get('%s_preview/%s/' % (page.get_absolute_url(), page.pk)), + self.assertEqual( + self.client.get(page.get_absolute_url()).status_code, 404) + self.assertContains( + self.client.get('%s_preview/%s/' % ( + page.get_absolute_url(), + page.pk), + ), 'Example content') def test_34_access(self): @@ -1379,7 +1610,11 @@ def test_34_access(self): Page.objects.update(active=True) self.login() - self.create_page_through_admin(title='redirect page', override_url='/', redirect_to=page.get_absolute_url(), active=True) + self.create_page_through_admin( + title='redirect page', + override_url='/', + redirect_to=page.get_absolute_url(), + active=True) # / -> redirect to /something/ r = self.client.get('/') @@ -1393,7 +1628,11 @@ def test_34_access(self): def test_35_access_with_extra_path(self): self.login() - self.create_page(title='redirect again', override_url='/', redirect_to='/somewhere/', active=True) + self.create_page( + title='redirect again', + override_url='/', + redirect_to='/somewhere/', + active=True) self.create_page(title='somewhere', active=True) r = self.client.get('/') diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 9b429d233..e06951b76 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -54,8 +54,10 @@ def test_region(self): class UtilsTest(TestCase): def test_get_object(self): - self.assertRaises(AttributeError, lambda: get_object('feincms.does_not_exist')) - self.assertRaises(ImportError, lambda: get_object('feincms.does_not_exist.fn')) + self.assertRaises( + AttributeError, lambda: get_object('feincms.does_not_exist')) + self.assertRaises( + ImportError, lambda: get_object('feincms.does_not_exist.fn')) self.assertEqual(get_object, get_object('feincms.utils.get_object')) @@ -86,7 +88,9 @@ def test_shorten_string(self): class ExampleCMSBase(Base): pass -ExampleCMSBase.register_regions(('region', 'region title'), ('region2', 'region2 title')) +ExampleCMSBase.register_regions( + ('region', 'region title'), + ('region2', 'region2 title')) class ExampleCMSBase2(Base): @@ -99,12 +103,14 @@ class ExampleCMSBase2(Base): Page.create_content_type(FileContent) Page.register_request_processor(processors.etag_request_processor) Page.register_response_processor(processors.etag_response_processor) -Page.register_response_processor(processors.debug_sql_queries_response_processor()) +Page.register_response_processor( + processors.debug_sql_queries_response_processor()) class BlogTestCase(TestCase): def setUp(self): - u = User(username='test', is_active=True, is_staff=True, is_superuser=True) + u = User(username='test', is_active=True, is_staff=True, + is_superuser=True) u.set_password('test') u.save() @@ -145,8 +151,10 @@ def test_01_smoke_test_admin(self): self.create_entry() self.login() - self.assertEqual(self.client.get('/admin/blog/entry/').status_code, 200) - self.assertEqual(self.client.get('/admin/blog/entry/1/').status_code, 200) + self.assertEqual( + self.client.get('/admin/blog/entry/').status_code, 200) + self.assertEqual( + self.client.get('/admin/blog/entry/1/').status_code, 200) def test_02_translations(self): self.create_entries() @@ -160,5 +168,7 @@ def test_02_translations(self): def test_03_admin(self): self.login() self.create_entries() - self.assertEqual(self.client.get('/admin/blog/entry/').status_code, 200) - self.assertEqual(self.client.get('/admin/blog/entry/1/').status_code, 200) + self.assertEqual( + self.client.get('/admin/blog/entry/').status_code, 200) + self.assertEqual( + self.client.get('/admin/blog/entry/1/').status_code, 200) From a1de1de7ffbbe5218e1f051aa2c50281f4f91b41 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 21 Nov 2013 15:58:06 +0100 Subject: [PATCH 0872/1590] Table content removal Refs #494. --- docs/api/contenttypes.rst | 7 - docs/contenttypes.rst | 12 - docs/releases/1.9.rst | 4 + feincms/content/table/__init__.py | 0 feincms/content/table/models.py | 100 ------- feincms/static/feincms/jquery.json-2.4.min.js | 23 -- .../templates/admin/content/table/init.html | 253 ------------------ 7 files changed, 4 insertions(+), 395 deletions(-) delete mode 100644 feincms/content/table/__init__.py delete mode 100644 feincms/content/table/models.py delete mode 100644 feincms/static/feincms/jquery.json-2.4.min.js delete mode 100644 feincms/templates/admin/content/table/init.html diff --git a/docs/api/contenttypes.rst b/docs/api/contenttypes.rst index 985d92c22..c5d81704b 100644 --- a/docs/api/contenttypes.rst +++ b/docs/api/contenttypes.rst @@ -71,13 +71,6 @@ SectionContent :members: :noindex: -TableContent ------------- - -.. automodule:: feincms.content.table.models - :members: - :noindex: - TemplateContent --------------- diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index b8048dbb4..329ded7f7 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -451,18 +451,6 @@ Section content Combined rich text editor, title and media file. -Table content -------------- -.. module:: feincms.content.table.models -.. class:: TableContent() - -The default configuration of the rich text editor does not include table -controls. Because of this, you can use this content type to provide HTML -table editing support. The data is stored in JSON format, additional -formatters can be easily written which produce the definitive HTML -representation of the table. - - Template content ---------------- .. module:: feincms.content.template.models diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index 02669e76b..93566fbde 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -23,6 +23,10 @@ Backwards-incompatible changes Removal of deprecated features ------------------------------ +* The table content type has been removed. It has open bugs for more than two + years which weren't fixed, and now that we've moved on to newer versions of + jQuery, the table content didn't even load. + * All extensions should inherit from ``feincms.extensions.Extension``. The support for ``register(cls, admin_cls)``-style functions has been removed. diff --git a/feincms/content/table/__init__.py b/feincms/content/table/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/feincms/content/table/models.py b/feincms/content/table/models.py deleted file mode 100644 index e4f141987..000000000 --- a/feincms/content/table/models.py +++ /dev/null @@ -1,100 +0,0 @@ -import json - -from django.db import models -from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ - - -class TableFormatter(object): - """ - Table formatter which should convert a structure of nested lists into - a suitable HTML table representation. - """ - - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - - def __call__(self, data): - return self.format_table(data) - - def format_table(self, data): - return u'<table class="table">%s</table>' % u''.join( - self.format_row(index, row) for index, row in enumerate(data)) - - def format_row(self, index, row): - self.row_index = index - return u'<tr>%s</tr>' % u''.join( - self.format_cell(index, cell) for index, cell in enumerate(row)) - - def format_cell(self, index, cell): - return u'<td>%s</td>' % cell - - -class TitleTableFormatter(TableFormatter): - """ - TitleTableFormatter(first_row_title=True, first_column_title=True) - """ - - def format_cell(self, index, cell): - if (not self.row_index and getattr(self, 'first_row_title', True)) or \ - (not index and getattr(self, 'first_column_title', True)): - return u'<th>%s</th>' % cell - return u'<td>%s</td>' % cell - - -class TableContent(models.Model): - """ - Content to edit and display HTML tables in the CMS. - - The standard rich text editor configuration in FeinCMS does not activate - the table plugin. This content type can be used to edit and display - nicely formatted HTML tables. It is easy to specify your own table - renderers. - """ - - feincms_item_editor_includes = { - 'head': ['admin/content/table/init.html'], - } - - html = models.TextField('HTML', blank=True, editable=False) - - DEFAULT_TYPES = [ - ('plain', _('plain'), TableFormatter()), - ('titlerow', _('title row'), TitleTableFormatter( - first_row_title=True, first_column_title=False)), - ('titlerowcol', _('title row and column'), TitleTableFormatter( - first_row_title=True, first_column_title=True)), - ] - - class Meta: - abstract = True - verbose_name = _('table') - verbose_name_plural = _('tables') - - @classmethod - def initialize_type(cls, TYPES=None): - TYPES = TYPES or cls.DEFAULT_TYPES - - cls.FORMATTERS = dict((t[0], t[2]) for t in TYPES) - cls.TYPE_CHOICES = [(t[0], t[1]) for t in TYPES] - - cls.add_to_class('type', models.CharField(_('type'), max_length=20, - choices=cls.TYPE_CHOICES, - default=cls.TYPE_CHOICES[0][0])) - - # Add after type, so that type comes before data in admin interface - cls.add_to_class('data', models.TextField(_('data'), blank=True)) - - def render(self, **kwargs): - return mark_safe(self.html) - - def save(self, *args, **kwargs): - # XXX ugly, but otherwise the decoder raises exceptions - self.data = self.data.replace( - '\r', '\\r').replace('\n', '\\n').replace('\t', '\\t') - self.html = self.data and self.FORMATTERS[self.type]( - json.loads(self.data)) or u'' - - super(TableContent, self).save(*args, **kwargs) - save.alters_data = True diff --git a/feincms/static/feincms/jquery.json-2.4.min.js b/feincms/static/feincms/jquery.json-2.4.min.js deleted file mode 100644 index 87050c9d9..000000000 --- a/feincms/static/feincms/jquery.json-2.4.min.js +++ /dev/null @@ -1,23 +0,0 @@ -/*! jQuery JSON plugin 2.4.0 | code.google.com/p/jquery-json */ -(function($){'use strict';var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},hasOwn=Object.prototype.hasOwnProperty;$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';} -var pairs,k,name,val,type=$.type(o);if(type==='undefined'){return undefined;} -if(type==='number'||type==='boolean'){return String(o);} -if(type==='string'){return $.quoteString(o);} -if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());} -if(type==='date'){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;} -if(day<10){day='0'+day;} -if(hours<10){hours='0'+hours;} -if(minutes<10){minutes='0'+minutes;} -if(seconds<10){seconds='0'+seconds;} -if(milli<100){milli='0'+milli;} -if(milli<10){milli='0'+milli;} -return'"'+year+'-'+month+'-'+day+'T'+ -hours+':'+minutes+':'+seconds+'.'+milli+'Z"';} -pairs=[];if($.isArray(o)){for(k=0;k<o.length;k++){pairs.push($.toJSON(o[k])||'null');} -return'['+pairs.join(',')+']';} -if(typeof o==='object'){for(k in o){if(hasOwn.call(o,k)){type=typeof k;if(type==='number'){name='"'+k+'"';}else if(type==='string'){name=$.quoteString(k);}else{continue;} -type=typeof o[k];if(type!=='function'&&type!=='undefined'){val=$.toJSON(o[k]);pairs.push(name+':'+val);}}} -return'{'+pairs.join(',')+'}';}};$.evalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){return eval('('+str+')');};$.secureEvalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){var filtered=str.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)){return eval('('+str+')');} -throw new SyntaxError('Error parsing JSON, source is not valid.');};$.quoteString=function(str){if(str.match(escape)){return'"'+str.replace(escape,function(a){var c=meta[a];if(typeof c==='string'){return c;} -c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';} -return'"'+str+'"';};}(jQuery)); \ No newline at end of file diff --git a/feincms/templates/admin/content/table/init.html b/feincms/templates/admin/content/table/init.html deleted file mode 100644 index 1f4b263e1..000000000 --- a/feincms/templates/admin/content/table/init.html +++ /dev/null @@ -1,253 +0,0 @@ -{% load i18n staticfiles %} -<script type="text/javascript" src="{% static 'feincms/jquery.json-2.4.min.js' %}"></script> -<script type="text/javascript"> -//<![CDATA[ - -/* - * Copyright (c) 2008 Greg Weber greg at gregweber.info - * Dual licensed under the MIT and GPL licenses - * - * jquery plugin - * make an html table editable by the user - * user clicks on a cell, edits the value, - * then presses enter or clicks on any cell to save the new value - * pressing escape returns the cell text to its orignal text - * - * documentation at http://gregweber.info/projects/uitableedit - * - * var t = $('table') - * $.uiTableEdit( t ) // returns t - * - * options : off, mouseDown, find, dataEntered, dataVerify, editDone - * off : turns off table editing - * find : defaults to tbody > tr > td - * mousedown : called in context of the table cell (as a normal event would be) - * if mouseDown returns false, cell will not become editable - * dataVerify : called in context of the cell, - * if dataVerify returns false, cell will stay in editable state - * if dataVerify returns text, that text will replace the cell's text - * arguments are the cell's text, original text, event, jquery object for the cell - * editDone : invoked on completion - * arguments: td cell's new text, original text, event, and jquery element for the td cell -*/ -(function($){ - $.uiTableEdit = function(jq, options){ - function unbind(){ - return jq.find( options.find ).unbind('mousedown.uiTableEdit') - } - options = options || {} - options.find = options.find || 'tbody > tr > td' - if( options.off ){ - unbind().find('form').each( function(){ var f = $(this); - f.parents("td:first").text( f.find(':text').attr('value') ); - f.remove(); - }); - return jq; - } - - function bind_mouse_down( mouseDn ){ - unbind().bind('mousedown.uiTableEdit', mouseDn ) - } - function td_edit(){ - var td = $(this); - - function restore(e){ - var val = td.find('textarea').val(); - if( options.dataVerify ){ - var value = options.dataVerify.call(this, val, orig_text, e, td); - if( value === false ){ return false; } - if( value !== null && value !== undefined ) val = value; - } - td.html( "" ); - td.text( val ); - if( options.editDone ) options.editDone(val,orig_text,e,td) - bind_mouse_down( td_edit_wrapper ); - } - - function checkEscape(e){ - if (e.keyCode === 27) { - td.html( "" ); - td.text( orig_text ); - bind_mouse_down( td_edit_wrapper ); - } else if (e.keyCode === 13 && !e.shiftKey) { - restore(e); - } - } - - var orig_text = td.text(); - var w = td.width(); - var h = td.height(); - td.html( '<form name="td-editor" action="javascript:void(0);">' + - '<textarea type="text" name="td_edit">' + td.text() + '</textarea></form>' ) - .find('form').submit( restore ).mousedown( restore ).blur( restore ).keypress( checkEscape ); - - var textarea = td.find('textarea'); - textarea.css('min-width', '150px').css('min-height', Math.max(150, textarea[0].scrollHeight)+'px'); - - function focus_text(){ td.find('textarea').get(0).focus() } - - // focus bug (seen in FireFox) fixed by small delay - setTimeout(focus_text, 50); - - /* TODO: investigate removing bind_mouse_down - I also got rid of bind_mouse_down(restore), - because now that you can refocus on fields that have been blurred, - you can have multiple edits going simultaneously - */ - bind_mouse_down( restore ); - } - - var td_edit_wrapper = !options.mouseDown ? td_edit : function(){ - if( options.mouseDown.apply(this,arguments) == false ) return false; - td_edit.apply(this,arguments); - }; - bind_mouse_down( td_edit_wrapper ); - return jq; - } - - function td_edit_editDone(value, original, event, td) { - var table = $(td).parents('table'); - var data = []; - table.find('tr').each(function(){ - var row = []; - $('td', this).each(function(){ - row.push($(this).html()); - }); - if(row.length) - data.push(row); - }); - - table.siblings('textarea').val($.toJSON(data)); - } - - var tablecontent_added = {}; - - contentblock_init_handlers.push(function(){ - $('.order-machine textarea[name*=tablecontent]').each(function(){ - if (tablecontent_added[this.id]) - return; - tablecontent_added[this.id] = true; - - var textarea = $(this); - var data = $.secureEvalJSON(textarea.val() || '[[""]]'); - - var html = '<table class="tablecontent" border="1">'; - - html += '<tr><th></th>'; - for(var i=0; i<data[0].length; i++) { - html += '<th><span class="remove-col">-</span> column <span class="insert-col">+</span></th>'; - } - html += '</tr>'; - - for(var i=0; i<data.length; i++) { - html += '<tr>'; - html += '<th><span class="remove-row">-</span> row <span class="insert-row">+</span></th>'; - for(var j=0; j<data[i].length; j++) { - html += '<td>'+data[i][j]+'</td>'; - } - html += '</tr>'; - } - - html += '</table>'; - - var table = textarea.hide().after(html).siblings('table'); - - $.uiTableEdit(table, {editDone: td_edit_editDone}); - }); - }); - - $('table.tablecontent th span.insert-col').live('click', function(){ - var row = $(this.parentNode.parentNode); - var index = row.find('th').index(this.parentNode)-1; // first row has empty TH at the beginning - var cell = $(this.parentNode); - var table = row.parents('table'); - - cell.after(cell.clone()); - table.find('tbody tr').each(function(){ - $('td:eq('+index+')', this).after('<td></td>'); - }); - - $.uiTableEdit(table, {editDone: td_edit_editDone}); - return false; - }); - - $('table.tablecontent th span.remove-col').live('click', function(){ - var row = $(this.parentNode.parentNode); - var index = row.find('th').index(this.parentNode)-1; // first row has empty TH at the beginning - var cell = $(this.parentNode); - var table = row.parents('table'); - - // prevent removal of last column - if(table.find('tr:eq(0) th').length<=2) - return false; - - cell.remove(); - table.find('tbody tr').each(function(){ - $('td:eq('+index+')', this).remove(); - }); - - $.uiTableEdit(table, {editDone: td_edit_editDone}); - return false; - }); - - $('table.tablecontent th span.insert-row').live('click', function(){ - var row = $(this.parentNode.parentNode); - var table = row.parents('table'); - - row.after(row.clone()).next().find('td').empty(); - - $.uiTableEdit(table, {editDone: td_edit_editDone}); - return false; - }); - - $('table.tablecontent th span.remove-row').live('click', function(){ - var table = $(this).parents('table'); - - if(table.find('tr').length<=2) - return false; - - $(this.parentNode.parentNode).remove(); - - // TODO regenerate JSON - - return false; - }); -})(feincms.jQuery); -//]]> - -</script> -<style type="text/css"> -table.tablecontent { - width: 620px; -} - -table.tablecontent th { - font-weight: normal; - background: #eef; - text-align: center; -} - -table.tablecontent th span { - cursor: pointer; -} - -table.tablecontent td { - border: 1px solid #cccccc; - white-space: pre-wrap; -} - -table.tablecontent form { - border: 1px dashed #000; - white-space: normal; -} - -table.tablecontent form textarea { - width: auto; - border: 0; - margin-top: 0; - margin-bottom: 0; - margin: 0 0 0 0; - padding: 0 0 0 0; - background: inherit; -} -</style> From ad614710dada77f8c6635a8e1c358e3df8acdab8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Nov 2013 14:30:44 +0100 Subject: [PATCH 0873/1590] E124 --- feincms/models.py | 5 +++-- feincms/module/mixins.py | 3 +-- setup.cfg | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 25da55c86..0e5aa15ab 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -374,9 +374,10 @@ def register_templates(cls, *templates): try: field = cls._meta.get_field_by_name('template_key')[0] except (FieldDoesNotExist, IndexError): - cls.add_to_class('template_key', + cls.add_to_class( + 'template_key', models.CharField(_('template'), max_length=255, choices=()) - ) + ) field = cls._meta.get_field_by_name('template_key')[0] def _template(self): diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index b397ed4fc..11fd6d5b6 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -192,8 +192,7 @@ def process_content_types(self): and extra_context.get('extra_path', '/') != '/' # XXX Already inside application content. I'm not sure # whether this fix is really correct... - and not extra_context.get('app_config') - ): + and not extra_context.get('app_config')): raise Http404('Not found (extra_path %r on %r)' % ( extra_context.get('extra_path', '/'), self.object, diff --git a/setup.cfg b/setup.cfg index 129c4cc68..1a738ac55 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [flake8] exclude=venv,.tox,build,docs -ignore=E123,E124,E128 +ignore=E123,E128 [wheel] universal = 1 From 4b96061371865fcc1eca668b195486e6a27355a7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 25 Nov 2013 14:59:39 +0100 Subject: [PATCH 0874/1590] E123 --- docs/releases/1.9.rst | 5 + example/admin.py | 2 +- example/models.py | 22 ++-- feincms/admin/filterspecs.py | 2 +- feincms/admin/item_editor.py | 10 +- feincms/admin/tree_editor.py | 14 ++- feincms/content/application/models.py | 4 +- feincms/content/comments/models.py | 14 +-- feincms/content/contactform/models.py | 8 +- feincms/content/file/models.py | 12 ++- feincms/content/image/models.py | 9 +- feincms/content/medialibrary/models.py | 2 +- feincms/content/richtext/models.py | 17 +-- feincms/content/rss/models.py | 13 ++- feincms/content/section/models.py | 15 +-- feincms/content/template/models.py | 2 +- feincms/content/video/models.py | 10 +- feincms/context_processors.py | 2 +- feincms/contrib/tagging.py | 2 +- feincms/default_settings.py | 101 +++++++++++++----- feincms/management/checker.py | 2 +- feincms/models.py | 27 ++--- .../module/blog/extensions/translations.py | 36 ++++--- feincms/module/blog/models.py | 4 +- feincms/module/extensions/ct_tracker.py | 11 +- feincms/module/extensions/datepublisher.py | 7 +- feincms/module/extensions/featured.py | 2 +- feincms/module/extensions/seo.py | 2 +- feincms/module/extensions/translations.py | 21 ++-- feincms/module/medialibrary/forms.py | 2 +- feincms/module/medialibrary/modeladmins.py | 19 ++-- feincms/module/medialibrary/models.py | 2 +- feincms/module/medialibrary/zip.py | 8 +- feincms/module/mixins.py | 2 +- feincms/module/page/extensions/excerpt.py | 2 +- feincms/module/page/extensions/navigation.py | 5 +- .../module/page/extensions/relatedpages.py | 2 +- feincms/module/page/extensions/titles.py | 2 +- feincms/module/page/forms.py | 10 +- feincms/module/page/modeladmins.py | 17 +-- feincms/module/page/models.py | 4 +- feincms/module/page/processors.py | 11 +- feincms/templatetags/feincms_tags.py | 2 +- feincms/templatetags/feincms_thumbnail.py | 5 +- feincms/translations.py | 27 +++-- feincms/utils/html/tidy.py | 2 +- setup.cfg | 2 +- tests/testapp/models.py | 25 ++--- tests/testapp/tests/test_extensions.py | 2 +- tests/testapp/tests/test_page.py | 87 ++++++++------- tests/testapp/tests/test_stuff.py | 17 +-- 51 files changed, 378 insertions(+), 255 deletions(-) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index 93566fbde..e31f7a308 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -53,6 +53,11 @@ Notable features and improvements and 1.10.3 respectively. Custom confirmation boxes have been removed and standard ones are used instead now. +* The diff between 1.8 and 1.9 is large -- most of it because of coding style + cleanups. `flake8 <https://pypi.python.org/pypi/flake8>`_ runs should not + show any warnings. The only error code we'll ignore for some time is + ``E128``. + Bugfixes ======== diff --git a/example/admin.py b/example/admin.py index 9df2fc47b..5c92e55d8 100644 --- a/example/admin.py +++ b/example/admin.py @@ -10,6 +10,6 @@ class CategoryAdmin(tree_editor.TreeEditor): list_filter = ('parent',) prepopulated_fields = { 'slug': ('name',), - } + } admin.site.register(Category, CategoryAdmin) diff --git a/example/models.py b/example/models.py index ce6fefcda..774c7c2bb 100644 --- a/example/models.py +++ b/example/models.py @@ -24,15 +24,15 @@ 'regions': ( ('main', 'Main region'), ('sidebar', 'Sidebar', 'inherited'), - ), - }) + ), +}) Page.create_content_type(RawContent) Page.create_content_type(MediaFileContent, TYPE_CHOICES=( ('default', 'Default position'), - )) +)) Page.create_content_type(ImageContent, POSITION_CHOICES=( ('default', 'Default position'), - )) +)) def get_admin_fields(form, *args, **kwargs): @@ -43,7 +43,7 @@ def get_admin_fields(form, *args, **kwargs): initial=form.instance.parameters.get('exclusive_subpages', False), help_text=_('Exclude everything other than the application\'s' ' content when rendering subpages.'), - ), + ), } @@ -51,17 +51,17 @@ def get_admin_fields(form, *args, **kwargs): ('blog_urls', 'Blog', { 'admin_fields': get_admin_fields, 'urls': 'example.blog_urls', - }), - )) + }), +)) Entry.register_regions( ('main', 'Main region'), - ) +) Entry.create_content_type(RawContent) Entry.create_content_type(ImageContent, POSITION_CHOICES=( ('default', 'Default position'), - )) +)) class BlogEntriesNavigationExtension(NavigationExtension): @@ -79,12 +79,12 @@ def children(self, page, **kwargs): url=app_reverse( 'blog_entry_detail', 'blog_urls', kwargs={'pk': entry.id}), level=page.level + 1, - ) + ) Page.register_extensions( 'feincms.module.page.extensions.navigation', 'feincms.module.page.extensions.sites', - ) +) @python_2_unicode_compatible diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index 380f1d44e..f5514aa55 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -36,7 +36,7 @@ def __init__(self, f, request, params, model, model_admin, self.lookup_choices = [( pk, "%s%s" % (" " * level, shorten_string(title, max_length=25)), - ) for pk, title, level in parents] + ) for pk, title, level in parents] def choices(self, cl): yield { diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 8bd91a05d..9469bd538 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -103,7 +103,7 @@ def get_feincms_inlines(self, model, request): attrs = { '__module__': model.__module__, 'model': content_type, - } + } if hasattr(content_type, 'feincms_item_editor_inline'): inline = content_type.feincms_item_editor_inline @@ -176,7 +176,7 @@ def _frontend_editing_view(self, request, cms_id, content_type, 'identifier': obj.fe_identifier(), 'FEINCMS_JQUERY_NO_CONFLICT': settings.FEINCMS_JQUERY_NO_CONFLICT, - }, context_instance=template.RequestContext(request)) + }, context_instance=template.RequestContext(request)) else: form = ModelForm(instance=obj, prefix=content_type) @@ -188,7 +188,7 @@ def _frontend_editing_view(self, request, cms_id, content_type, 'form': form, 'is_popup': True, 'media': self.media, - }) + }) return render_to_response('admin/feincms/fe_editor.html', context, context_instance=template.RequestContext(request)) @@ -217,7 +217,7 @@ def get_extra_context(self, request): 'FEINCMS_FRONTEND_EDITING': settings.FEINCMS_FRONTEND_EDITING, 'FEINCMS_POPUP_VAR': is_popup_var(), - } + } for processor in self.model.feincms_item_editor_context_processors: extra_context.update(processor(request)) @@ -317,7 +317,7 @@ def get_template_list(self): opts.app_label, opts.object_name.lower()), 'admin/feincms/%s/item_editor.html' % opts.app_label, 'admin/feincms/item_editor.html', - ] + ] def get_fieldsets(self, request, obj=None): """ diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index ed37580c4..46daaafed 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -114,7 +114,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): item.pk, attr, 'checked="checked"' if value else '', - )] + )] a.insert(0, '<div id="wrap_%s_%d">' % (attr, item.pk)) a.append('</div>') @@ -239,7 +239,7 @@ def __init__(self, *args, **kwargs): opts.app_label, opts.object_name.lower()), 'admin/feincms/%s/tree_editor.html' % opts.app_label, 'admin/feincms/tree_editor.html', - ] + ] self.object_change_permission =\ opts.app_label + '.' + opts.get_change_permission() self.object_add_permission =\ @@ -388,9 +388,9 @@ def _toggle_boolean(self, request): # Weed out unchanged cells to keep the updates small. This assumes # that the order a possible get_descendents() returns does not change # before and after toggling this attribute. Unlikely, but still... - return HttpResponse(json.dumps( - [b for a, b in zip(before_data, data) if a != b] - ), content_type="application/json") + return HttpResponse( + json.dumps([b for a, b in zip(before_data, data) if a != b]), + content_type="application/json") def get_changelist(self, request, **kwargs): return ChangeList @@ -531,9 +531,7 @@ def delete_selected_tree(self, modeladmin, request, queryset): "Denied delete request by \"%s\" for object #%s", request.user, obj.id) self.message_user(request, - _("Successfully deleted %(count)d items.") % { - "count": n - }) + _("Successfully deleted %(count)d items.") % {"count": n}) # Return None to display the change list page again return None else: diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index cc23eb921..26e07a2ff 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -370,7 +370,7 @@ def closest_match(cls, urlconf_path): contents = cls.objects.filter( parent__in=page_class.objects.active(), urlconf_path=urlconf_path, - ).order_by('pk').select_related('parent') + ).order_by('pk').select_related('parent') if len(contents) > 1: try: @@ -378,7 +378,7 @@ def closest_match(cls, urlconf_path): return [ content for content in contents if short_language_code(content.parent.language) == current - ][0] + ][0] except (AttributeError, IndexError): pass diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index 654bc7b73..a9907e954 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -57,7 +57,7 @@ def __init__(self, *args, **kwargs): else _('not public')), 'app': comments_model._meta.app_label, 'model': comments_model._meta.module_name, - } + } f.help_text = r cls.feincms_item_editor_form = CommentContentAdminForm @@ -91,17 +91,19 @@ def process(self, request, **kwargs): if f is None: f = comments.get_form()(comment_page) - self.rendered_output = render_to_string([ - 'content/comments/%s.html' % parent_type, - 'content/comments/default-site.html', - 'content/comments/default.html', + self.rendered_output = render_to_string( + [ + 'content/comments/%s.html' % parent_type, + 'content/comments/default-site.html', + 'content/comments/default.html', ], RequestContext(request, { 'content': self, 'feincms_page': self.parent, 'parent': comment_page, 'form': f, - })) + }), + ) def render(self, **kwargs): return getattr(self, 'rendered_output', u'') diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index e4ac6b807..1e60802d9 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -54,10 +54,11 @@ def process(self, request, **kwargs): form.cleaned_data['subject'], render_to_string('content/contactform/email.txt', { 'data': form.cleaned_data, - }), + }), form.cleaned_data['email'], [self.email], - fail_silently=True) + fail_silently=True, + ) return HttpResponseRedirect('?_cf_thanks=1') else: @@ -72,7 +73,8 @@ def process(self, request, **kwargs): 'content/contactform/form.html', { 'content': self, 'form': form, - }, context_instance=RequestContext(request)) + }, + context_instance=RequestContext(request)) def render(self, **kwargs): return getattr(self, 'rendered_output', u'') diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index 9f2be2c9a..105158250 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -27,7 +27,11 @@ class Meta: verbose_name_plural = _('files') def render(self, **kwargs): - return render_to_string([ - 'content/file/%s.html' % self.region, - 'content/file/default.html', - ], {'content': self}, context_instance=kwargs.get('context')) + return render_to_string( + [ + 'content/file/%s.html' % self.region, + 'content/file/default.html', + ], + {'content': self}, + context_instance=kwargs.get('context'), + ) diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index 360965c1a..47a12c461 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -60,7 +60,8 @@ def render(self, **kwargs): return render_to_string( templates, {'content': self}, - context_instance=kwargs.get('context')) + context_instance=kwargs.get('context'), + ) def get_image(self): type, separator, size = getattr(self, 'format', '').partition(':') @@ -69,7 +70,7 @@ def get_image(self): thumbnailer = { 'cropscale': feincms_thumbnail.CropscaleThumbnailer, - }.get(type, feincms_thumbnail.Thumbnailer) + }.get(type, feincms_thumbnail.Thumbnailer) return thumbnailer(self.image, size) @classmethod @@ -80,7 +81,7 @@ def initialize_type(cls, POSITION_CHOICES=None, FORMAT_CHOICES=None): max_length=10, choices=POSITION_CHOICES, default=POSITION_CHOICES[0][0] - ).contribute_to_class(cls, 'position') + ).contribute_to_class(cls, 'position') if FORMAT_CHOICES: models.CharField( @@ -88,4 +89,4 @@ def initialize_type(cls, POSITION_CHOICES=None, FORMAT_CHOICES=None): max_length=64, choices=FORMAT_CHOICES, default=FORMAT_CHOICES[0][0] - ).contribute_to_class(cls, 'format') + ).contribute_to_class(cls, 'format') diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index c22c7d13f..f95ed4b77 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -66,4 +66,4 @@ def render(self, **kwargs): 'content/mediafile/%s.html' % self.mediafile.type, 'content/mediafile/%s.html' % self.type, 'content/mediafile/default.html', - ], ctx, context_instance=kwargs.get('context')) + ], ctx, context_instance=kwargs.get('context')) diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 17f425e55..98ecdeacd 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -48,13 +48,16 @@ def clean(self): if errors or not ( settings.FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE and cleaned_data['seen_tidy_warnings']): - self._errors["text"] = ErrorList([mark_safe(_( - "HTML validation produced %(count)d warnings." - " Please review the updated content below before" - " continuing: %(messages)s") % { - "count": len(warnings) + len(errors), - "messages": '<ul><li>%s</li></ul>' % ( - "</li><li>".join(map(escape, errors + warnings))), + self._errors["text"] = ErrorList([mark_safe( + _( + "HTML validation produced %(count)d warnings." + " Please review the updated content below before" + " continuing: %(messages)s" + ) % { + "count": len(warnings) + len(errors), + "messages": '<ul><li>%s</li></ul>' % ( + "</li><li>".join( + map(escape, errors + warnings))), } )]) diff --git a/feincms/content/rss/models.py b/feincms/content/rss/models.py index 2cc788d73..789d399e8 100644 --- a/feincms/content/rss/models.py +++ b/feincms/content/rss/models.py @@ -44,11 +44,14 @@ def cache_content(self, date_format=None, save=True): entry.updated = time.strftime(date_format, entry.updated_parsed) - self.rendered_content = render_to_string('content/rss/content.html', { - 'feed_title': self.title, - 'feed_link': feed['feed'].get('link'), - 'entries': entries, - }) + self.rendered_content = render_to_string( + 'content/rss/content.html', + { + 'feed_title': self.title, + 'feed_link': feed['feed'].get('link'), + 'entries': entries, + }, + ) self.last_updated = timezone.now() if save: diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 2b1831709..a85304c3c 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -71,12 +71,15 @@ def render(self, **kwargs): else: mediafile_type = 'nomedia' - return render_to_string([ - 'content/section/%s_%s.html' % (mediafile_type, self.type), - 'content/section/%s.html' % mediafile_type, - 'content/section/%s.html' % self.type, - 'content/section/default.html', - ], {'content': self}) + return render_to_string( + [ + 'content/section/%s_%s.html' % (mediafile_type, self.type), + 'content/section/%s.html' % mediafile_type, + 'content/section/%s.html' % self.type, + 'content/section/default.html', + ], + {'content': self}, + ) def save(self, *args, **kwargs): if getattr(self, 'cleanse', None): diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index d78755b35..03163136d 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -9,7 +9,7 @@ DEFAULT_TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', - ) +) class TemplateChoices(object): diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index 824a9424d..f5a1abe74 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -19,14 +19,14 @@ class VideoContent(models.Model): PORTALS = ( ('youtube', re.compile(r'youtube'), lambda url: { 'v': re.search(r'([?&]v=|./././)([^#&]+)', url).group(2), - }), + }), ('vimeo', re.compile(r'vimeo'), lambda url: { 'id': re.search(r'/(\d+)', url).group(1), - }), + }), ('sf', re.compile(r'sf\.tv'), lambda url: { 'id': re.search(r'/([a-z0-9\-]+)', url).group(1), - }), - ) + }), + ) video = models.URLField(_('video link'), help_text=_('This should be a link to a youtube or vimeo video,' @@ -46,7 +46,7 @@ def get_templates(self, portal='unknown'): return [ 'content/video/%s.html' % portal, 'content/video/unknown.html', - ] + ] def ctx_for_video(self, vurl): "Get a context dict for a given video URL" diff --git a/feincms/context_processors.py b/feincms/context_processors.py index ae9638d96..3f5c9b1a7 100644 --- a/feincms/context_processors.py +++ b/feincms/context_processors.py @@ -9,6 +9,6 @@ def add_page_if_missing(request): try: return { 'feincms_page': Page.objects.for_request(request, best_match=True), - } + } except Page.DoesNotExist: return {} diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 48afc4e84..d325508b8 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -113,7 +113,7 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, cls.add_to_class(field_name, ( TagSelectField if select_field else TagField - )(field_name.capitalize(), blank=True)) + )(field_name.capitalize(), blank=True)) # use another name for the tag descriptor # See http://code.google.com/p/django-tagging/issues/detail?id=95 for the # reason why diff --git a/feincms/default_settings.py b/feincms/default_settings.py index ae41a036e..6db7eb510 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -17,74 +17,98 @@ # e.g. 'uploads' if you would prefer <media root>/uploads/imagecontent/test.jpg # to <media root>/imagecontent/test.jpg. -FEINCMS_UPLOAD_PREFIX = getattr(settings, 'FEINCMS_UPLOAD_PREFIX', '') +FEINCMS_UPLOAD_PREFIX = getattr( + settings, + 'FEINCMS_UPLOAD_PREFIX', + '') # ------------------------------------------------------------------------ # Settings for MediaLibrary #: Local path to newly uploaded media files -FEINCMS_MEDIALIBRARY_UPLOAD_TO = getattr(settings, - 'FEINCMS_MEDIALIBRARY_UPLOAD_TO', 'medialibrary/%Y/%m/') +FEINCMS_MEDIALIBRARY_UPLOAD_TO = getattr( + settings, + 'FEINCMS_MEDIALIBRARY_UPLOAD_TO', + 'medialibrary/%Y/%m/') #: Thumbnail function for suitable mediafiles. Only receives the media file #: and should return a thumbnail URL (or nothing). -FEINCMS_MEDIALIBRARY_THUMBNAIL = getattr(settings, +FEINCMS_MEDIALIBRARY_THUMBNAIL = getattr( + settings, 'FEINCMS_MEDIALIBRARY_THUMBNAIL', 'feincms.module.medialibrary.thumbnail.default_admin_thumbnail') # ------------------------------------------------------------------------ # Settings for RichText -FEINCMS_RICHTEXT_INIT_TEMPLATE = getattr(settings, +FEINCMS_RICHTEXT_INIT_TEMPLATE = getattr( + settings, 'FEINCMS_RICHTEXT_INIT_TEMPLATE', 'admin/content/richtext/init_tinymce.html') -FEINCMS_RICHTEXT_INIT_CONTEXT = getattr(settings, +FEINCMS_RICHTEXT_INIT_CONTEXT = getattr( + settings, 'FEINCMS_RICHTEXT_INIT_CONTEXT', { 'TINYMCE_JS_URL': join(settings.MEDIA_URL, 'js/tiny_mce/tiny_mce.js'), 'TINYMCE_DOMAIN': None, 'TINYMCE_CONTENT_CSS_URL': None, 'TINYMCE_LINK_LIST_URL': None - }) + } +) # ------------------------------------------------------------------------ # Admin media settings #: avoid jQuery conflicts -- scripts should use feincms.jQuery instead of $ -FEINCMS_JQUERY_NO_CONFLICT = getattr(settings, 'FEINCMS_JQUERY_NO_CONFLICT', +FEINCMS_JQUERY_NO_CONFLICT = getattr( + settings, + 'FEINCMS_JQUERY_NO_CONFLICT', False) # ------------------------------------------------------------------------ # Settings for the page module #: Include ancestors in filtered tree editor lists -FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS = getattr(settings, - 'FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS', False) +FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS = getattr( + settings, + 'FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS', + False) #: Show frontend-editing button? -FEINCMS_FRONTEND_EDITING = getattr(settings, 'FEINCMS_FRONTEND_EDITING', +FEINCMS_FRONTEND_EDITING = getattr( + settings, + 'FEINCMS_FRONTEND_EDITING', False) #: Enable checking of object level permissions. Note that if this option is #: enabled, you must plug in an authentication backend that actually does #: implement object level permissions or no page will be editable. -FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS = getattr(settings, - 'FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS', False) +FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS = getattr( + settings, + 'FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS', + False) #: When enabled, the page module is automatically registered with Django's #: default admin site (this is activated by default). -FEINCMS_USE_PAGE_ADMIN = getattr(settings, 'FEINCMS_USE_PAGE_ADMIN', True) +FEINCMS_USE_PAGE_ADMIN = getattr( + settings, + 'FEINCMS_USE_PAGE_ADMIN', + True) #: app_label.model_name as per django.db.models.get_model. #: defaults to page.Page FEINCMS_DEFAULT_PAGE_MODEL = getattr( - settings, 'FEINCMS_DEFAULT_PAGE_MODEL', 'page.Page') + settings, + 'FEINCMS_DEFAULT_PAGE_MODEL', + 'page.Page') # ------------------------------------------------------------------------ # Various settings # ------------------------------------------------------------------------ #: Allow random gunk after a valid page? -FEINCMS_ALLOW_EXTRA_PATH = getattr(settings, 'FEINCMS_ALLOW_EXTRA_PATH', +FEINCMS_ALLOW_EXTRA_PATH = getattr( + settings, + 'FEINCMS_ALLOW_EXTRA_PATH', False) # ------------------------------------------------------------------------ @@ -93,25 +117,36 @@ #: and overwrites whatever was set before. #: * ``'EXPLICIT'``: The language set has priority, may only be overridden #: by explicitely a language with ``?set_language=xx``. -FEINCMS_TRANSLATION_POLICY = getattr(settings, 'FEINCMS_TRANSLATION_POLICY', +FEINCMS_TRANSLATION_POLICY = getattr( + settings, + 'FEINCMS_TRANSLATION_POLICY', 'STANDARD') # ------------------------------------------------------------------------ # Settings for HTML validation #: If True, HTML will be run through a tidy function before saving: -FEINCMS_TIDY_HTML = getattr(settings, 'FEINCMS_TIDY_HTML', False) +FEINCMS_TIDY_HTML = getattr( + settings, + 'FEINCMS_TIDY_HTML', + False) #: If True, displays form validation errors so the user can see how their #: HTML has been changed: -FEINCMS_TIDY_SHOW_WARNINGS = getattr(settings, 'FEINCMS_TIDY_SHOW_WARNINGS', +FEINCMS_TIDY_SHOW_WARNINGS = getattr( + settings, + 'FEINCMS_TIDY_SHOW_WARNINGS', True) #: If True, users will be allowed to ignore HTML warnings (errors are always #: blocked): -FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE = getattr(settings, - 'FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE', True) +FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE = getattr( + settings, + 'FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE', + True) #: Name of the tidy function - anything which takes ``(html)`` and returns #: ``(html, errors, warnings)`` can be used: -FEINCMS_TIDY_FUNCTION = getattr(settings, 'FEINCMS_TIDY_FUNCTION', +FEINCMS_TIDY_FUNCTION = getattr( + settings, + 'FEINCMS_TIDY_FUNCTION', 'feincms.utils.html.tidy.tidy_html') # ------------------------------------------------------------------------ @@ -120,31 +155,43 @@ #: customised cms-styled error pages. Do not go overboard, this should #: be as simple and as error resistant as possible, so refrain from #: deeply nested error pages or advanced content types. -FEINCMS_CMS_404_PAGE = getattr(settings, 'FEINCMS_CMS_404_PAGE', None) +FEINCMS_CMS_404_PAGE = getattr( + settings, + 'FEINCMS_CMS_404_PAGE', + None) # ------------------------------------------------------------------------ #: When uploading files to the media library, replacing an existing entry, #: try to save the new file under the old file name in order to keep the #: media file path (and thus the media url) constant. #: Experimental, this might not work with all storage backends. -FEINCMS_MEDIAFILE_OVERWRITE = getattr(settings, 'FEINCMS_MEDIAFILE_OVERWRITE', +FEINCMS_MEDIAFILE_OVERWRITE = getattr( + settings, + 'FEINCMS_MEDIAFILE_OVERWRITE', False) # ------------------------------------------------------------------------ #: Prefix for thumbnails. Set this to something non-empty to separate thumbs #: from uploads. The value should end with a slash, but this is not enforced. -FEINCMS_THUMBNAIL_DIR = getattr(settings, 'FEINCMS_THUMBNAIL_DIR', '_thumbs/') +FEINCMS_THUMBNAIL_DIR = getattr( + settings, + 'FEINCMS_THUMBNAIL_DIR', + '_thumbs/') # ------------------------------------------------------------------------ #: Prevent changing template within admin for pages which have been #: allocated a Template with singleton=True -- template field will become #: read-only for singleton pages. FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED = getattr( - settings, 'FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED', False) + settings, + 'FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED', + False) #: Prevent admin page deletion for pages which have been allocated a #: Template with singleton=True FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED = getattr( - settings, 'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED', False) + settings, + 'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED', + False) # ------------------------------------------------------------------------ diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 7775a4582..363dc40ab 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -53,7 +53,7 @@ def _fn(sender, **kwargs): ' ' * (25 - len(field.column)), u'%s.%s' % ( field.__class__.__module__, field.__class__.__name__), - )) + )) print(style.NOTICE( '\nPlease consult the output of `python manage.py sql %s` to' diff --git a/feincms/models.py b/feincms/models.py index 0e5aa15ab..579c0b7fb 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -106,7 +106,7 @@ def __init__(self, item): self.db = item._state.db self._cache = { 'cts': {}, - } + } def _inherit_from(self): """ @@ -163,7 +163,7 @@ def _fetch_content_type_counts(self): def _fetch_content_type_count_helper(self, pk, regions=None): tmpl = [ 'SELECT %d AS ct_idx, region, COUNT(id) FROM %s WHERE parent_id=%s' - ] + ] args = [] if regions: @@ -199,7 +199,7 @@ def _popuplate_content_type_caches(self, types): counts_by_type.setdefault( self.item._feincms_content_types[ct_idx], [], - ).append((region, pk)) + ).append((region, pk)) # Resolve abstract to concrete content types content_types = (cls for cls in self.item._feincms_content_types @@ -228,10 +228,12 @@ def _fetch_regions(self): for instance in content_list: contents.setdefault(instance.region, []).append(instance) - self._cache['regions'] = dict(( - region, - sorted(instances, key=lambda c: c.ordering), - ) for region, instances in contents.items()) + self._cache['regions'] = dict( + ( + region, + sorted(instances, key=lambda c: c.ordering), + ) for region, instances in contents.items() + ) return self._cache['regions'] @@ -485,7 +487,7 @@ def fe_render(self, **kwargs): return render_to_string('admin/feincms/fe_box.html', { 'content': self.render(**kwargs), 'identifier': self.fe_identifier(), - }) + }) return self.render(**kwargs) @@ -503,7 +505,7 @@ def fe_identifier(self): self.__class__.__name__.lower(), self.parent_id, self.id, - ) + ) def get_queryset(cls, filter_args): return cls.objects.select_related().filter(filter_args) @@ -525,7 +527,7 @@ def get_queryset(cls, filter_args): 'parent': models.ForeignKey(cls, related_name='%(class)s_set'), 'region': models.CharField(max_length=255), 'ordering': models.IntegerField(_('ordering'), default=0), - } + } # create content base type and save reference on CMS class @@ -676,12 +678,13 @@ class Meta(feincms_content_base.Meta): # the blog and the page module). '__module__': cls.__module__, 'Meta': Meta, - } + } new_type = type( class_name, (model, feincms_content_base,), - attrs) + attrs, + ) cls._feincms_content_types.append(new_type) # For consistency's sake, also install the new type in the module setattr(sys.modules[cls.__module__], class_name, new_type) diff --git a/feincms/module/blog/extensions/translations.py b/feincms/module/blog/extensions/translations.py index f5ef62eea..704ef4788 100644 --- a/feincms/module/blog/extensions/translations.py +++ b/feincms/module/blog/extensions/translations.py @@ -17,16 +17,26 @@ class Extension(extensions.Extension): def handle_model(self): primary_language = settings.LANGUAGES[0][0] - self.model.add_to_class('language', models.CharField( - _('language'), max_length=10, - choices=settings.LANGUAGES)) - self.model.add_to_class('translation_of', models.ForeignKey('self', - blank=True, null=True, verbose_name=_('translation of'), - related_name='translations', - limit_choices_to={'language': primary_language}, - help_text=_( - 'Leave this empty for entries in the primary language.') - )) + self.model.add_to_class( + 'language', + models.CharField( + _('language'), + max_length=10, + choices=settings.LANGUAGES, + ) + ) + self.model.add_to_class( + 'translation_of', + models.ForeignKey( + 'self', + blank=True, null=True, + verbose_name=_('translation of'), + related_name='translations', + limit_choices_to={'language': primary_language}, + help_text=_( + 'Leave this empty for entries in the primary language.'), + ) + ) def available_translations(self): if self.language == primary_language: @@ -45,8 +55,10 @@ def available_translations_admin(self): return u', '.join( u'<a href="%s/">%s</a>' % ( - page.id, page.language.upper() - ) for page in translations) + page.id, + page.language.upper() + ) for page in translations + ) available_translations_admin.allow_tags = True available_translations_admin.short_description =\ diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index 88497af54..48e2bcb73 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -22,7 +22,7 @@ def published(self): published=True, published_on__isnull=False, published_on__lte=timezone.now(), - ) + ) @python_2_unicode_compatible @@ -69,6 +69,6 @@ class EntryAdmin(item_editor.ItemEditor): search_fields = ['title', 'slug'] prepopulated_fields = { 'slug': ('title',), - } + } raw_id_fields = [] diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index de89238e3..d889d8d62 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -103,14 +103,17 @@ def _from_inventory(self, inventory): return dict((region, [ (pk, map[-ct]) for pk, ct in items - ]) for region, items in inventory.items() if region != '_version_') + ]) for region, items in inventory.items() if region != '_version_') def _to_inventory(self, counts): map = self._translation_map() - inventory = dict((region, [ - (pk, map[ct]) for pk, ct in items - ]) for region, items in counts.items()) + inventory = dict( + ( + region, + [(pk, map[ct]) for pk, ct in items], + ) for region, items in counts.items() + ) inventory['_version_'] = INVENTORY_VERSION return inventory diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 5f327a097..1d9cad8bc 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -105,7 +105,8 @@ def granular_save(obj, *args, **kwargs): Q(publication_date__lte=granular_now) & (Q(publication_end_date__isnull=True) | Q(publication_end_date__gt=granular_now)), - key='datepublisher') + key='datepublisher', + ) # Processor to patch up response headers for expiry date self.model.register_response_processor( @@ -116,7 +117,7 @@ def datepublisher_admin(self, obj): return u'%s – %s' % ( format_date(obj.publication_date), format_date(obj.publication_end_date, '∞'), - ) + ) datepublisher_admin.allow_tags = True datepublisher_admin.short_description = _('visible from - to') @@ -131,6 +132,6 @@ def datepublisher_admin(self, obj): modeladmin.add_extension_options(_('Date-based publishing'), { 'fields': ['publication_date', 'publication_end_date'], - }) + }) # ------------------------------------------------------------------------ diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index d130aa855..39ae62bc2 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -19,4 +19,4 @@ def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Featured'), { 'fields': ('featured',), 'classes': ('collapse',), - }) + }) diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index f3aa724de..4bf689a63 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -27,4 +27,4 @@ def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Search engine optimization'), { 'fields': ('meta_keywords', 'meta_description'), 'classes': ('collapse',), - }) + }) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 2909de1f8..4df7948f0 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -136,13 +136,16 @@ def handle_model(self): max_length=10, choices=django_settings.LANGUAGES, default=django_settings.LANGUAGES[0][0])) - cls.add_to_class('translation_of', models.ForeignKey('self', - blank=True, null=True, verbose_name=_('translation of'), - related_name='translations', - limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, - help_text=_( - 'Leave this empty for entries in the primary language.') - )) + cls.add_to_class( + 'translation_of', + models.ForeignKey('self', + blank=True, null=True, verbose_name=_('translation of'), + related_name='translations', + limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, + help_text=_( + 'Leave this empty for entries in the primary language.'), + ) + ) if hasattr(cls, 'register_request_processor'): if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": @@ -235,7 +238,9 @@ def available_translations_admin(self, page): page.id, key, _('Create translation'), - key.upper())) + key.upper() + ) + ) return u' | '.join(links) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 01db7f27b..38d5f6425 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -71,7 +71,7 @@ def clean_file(self): raise forms.ValidationError(_( "Cannot overwrite with different file type (attempt to" " overwrite a %(old_ext)s with a %(new_ext)s)" - ) % {'old_ext': old_ext, 'new_ext': new_ext}) + ) % {'old_ext': old_ext, 'new_ext': new_ext}) self.instance.original_name = self.instance.file.name diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 9d11ba4d9..21cc77037 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -72,13 +72,13 @@ class AddCategoryForm(forms.Form): form = AddCategoryForm(initial={ '_selected_action': request.POST.getlist( admin.ACTION_CHECKBOX_NAME), - }) + }) return render_to_response('admin/medialibrary/add_to_category.html', { 'mediafiles': queryset, 'category_form': form, 'opts': modeladmin.model._meta, - }, context_instance=RequestContext(request)) + }, context_instance=RequestContext(request)) assign_category.short_description = _('Add selected media files to category') @@ -125,10 +125,12 @@ def get_urls(self): urls = super(MediaFileAdmin, self).get_urls() my_urls = patterns('', - url(r'^mediafile-bulk-upload/$', + url( + r'^mediafile-bulk-upload/$', self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, - name='mediafile_bulk_upload'), - ) + name='mediafile_bulk_upload', + ), + ) return my_urls + urls @@ -147,7 +149,8 @@ def admin_thumbnail(self, obj): <img src="%(image)s" alt="" /> </a>""" % { 'url': obj.file.url, - 'image': image}) + 'image': image} + ) return '' admin_thumbnail.short_description = _('Preview') admin_thumbnail.allow_tags = True @@ -194,14 +197,14 @@ def file_info(self, obj): u'<input type="hidden" class="medialibrary_file_path"' u' name="_media_path_%d" value="%s" id="_refkey_%d" />' u' %s <br />%s, %s' - ) % ( + ) % ( obj.id, obj.file.name, obj.id, shorten_string(os.path.basename(obj.file.name), max_length=40), self.file_type(obj), self.formatted_file_size(obj), - ) + ) file_info.admin_order_field = 'file' file_info.short_description = _('file info') file_info.allow_tags = True diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 5633891e6..bae431a73 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -232,7 +232,7 @@ def delete_mediafile(self, name=None): ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile( r'\.pptx?$', re.IGNORECASE).search(f)), ('other', _('Binary'), lambda f: True), # Must be last - ) +) # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 5751e05bd..d4a8109b9 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -158,8 +158,8 @@ def export_zipfile(site, queryset): 'slug': cat.slug, 'parent': cat.parent_id or 0, 'level': len(cat.path_list()), - } for cat in used_categories], - } + } for cat in used_categories], + } zip_file.comment = json.dumps(info) for mf in queryset: @@ -171,8 +171,8 @@ def export_zipfile(site, queryset): 'lang': t.language_code, 'caption': t.caption, 'description': t.description, - } for t in mf.translations.all()], - }) + } for t in mf.translations.all()], + }) with open(mf.file.path, "r") as file_data: zip_info = zipfile.ZipInfo( diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 11fd6d5b6..4b7299351 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -196,7 +196,7 @@ def process_content_types(self): raise Http404('Not found (extra_path %r on %r)' % ( extra_context.get('extra_path', '/'), self.object, - )) + )) def finalize_content_types(self, response): """ diff --git a/feincms/module/page/extensions/excerpt.py b/feincms/module/page/extensions/excerpt.py index 3861a7a1f..5cc3be28d 100644 --- a/feincms/module/page/extensions/excerpt.py +++ b/feincms/module/page/extensions/excerpt.py @@ -20,4 +20,4 @@ def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Excerpt'), { 'fields': ('excerpt',), 'classes': ('collapse',), - }) + }) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 1bf54e5eb..a3085b942 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -105,7 +105,8 @@ class Extension(extensions.Extension): ident = 'navigation' # TODO actually use this def handle_model(self): - self.model.add_to_class('navigation_extension', + self.model.add_to_class( + 'navigation_extension', models.CharField( _('navigation extension'), choices=navigation_extension_choices(), @@ -129,4 +130,4 @@ def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Navigation extension'), { 'fields': ('navigation_extension',), 'classes': ('collapse',), - }) + }) diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 0bf949a01..43f5411ab 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -26,4 +26,4 @@ def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Related pages'), { 'fields': ('related_pages',), 'classes': ('collapse',), - }) + }) diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index a2a5acc13..e92f7000f 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -56,4 +56,4 @@ def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Titles'), { 'fields': ('_content_title', '_page_title'), 'classes': ('collapse',), - }) + }) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index fcb41edc8..0609ba135 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -93,13 +93,13 @@ def __init__(self, *args, **kwargs): 'template_key': original.template_key, 'active': original.active, 'in_navigation': original.in_navigation, - } + } if original.parent: try: data['parent'] = original.parent.get_translation( kwargs['initial']['language'] - ).id + ).id except self.page_model.DoesNotExist: # ignore this -- the translation does not exist pass @@ -131,12 +131,14 @@ def __init__(self, *args, **kwargs): if template.singleton and other_pages_for_template.exists(): continue # don't allow selection of singleton if in use if template.preview_image: - choices.append((template.key, + choices.append(( + template.key, mark_safe(u'<img src="%s" alt="%s" /> %s' % ( template.preview_image, template.key, template.title, - )))) + )) + )) else: choices.append((template.key, template.title)) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 5e1412dec..3c6caf105 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -37,7 +37,7 @@ class Media: 'fields': [ ('title', 'slug'), ('active', 'in_navigation'), - ], + ], }), (_('Other options'), { 'classes': ['collapse'], @@ -47,7 +47,7 @@ class Media: # <-- insertion point, extensions appear here, see insertion_index # above item_editor.FEINCMS_CONTENT_FIELDSET, - ] + ] readonly_fields = [] list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] @@ -142,7 +142,7 @@ def add_view(self, request, **kwargs): 'Add %(language)s translation of "%(page)s"') % { 'language': language, 'page': original, - }, + }, 'language_name': language, 'translation_of': original, } @@ -190,9 +190,14 @@ def change_view(self, request, object_id, **kwargs): return super(PageAdmin, self).change_view( request, object_id, **kwargs) except PermissionDenied: - messages.add_message(request, messages.ERROR, _( - "You don't have the necessary permissions to edit this object" - )) + messages.add_message( + request, + messages.ERROR, + _( + "You don't have the necessary permissions to edit this" + " object" + ) + ) return HttpResponseRedirect(reverse('admin:page_page_changelist')) def has_delete_permission(self, request, obj=None): diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index ff8a39686..91e66dd89 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -98,7 +98,7 @@ def best_match_for_path(self, path, raise404=False): try: page = self.active().filter(_cached_url__in=paths).extra( select={'_url_length': 'LENGTH(_cached_url)'} - ).order_by('-_url_length')[0] + ).order_by('-_url_length')[0] if not page.are_ancestors_active(): raise IndexError('Parents are inactive.') @@ -323,7 +323,7 @@ def get_navigation_url(self): lambda p: getattr(django_settings, 'SITE_ID', 0), lambda p: p._django_content_type.id, lambda p: p.id, - ] + ] def cache_key(self): """ diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 48b8f87f7..722f81182 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -28,15 +28,18 @@ def extra_context_request_processor(page, request): # XXX This variable name isn't accurate anymore. 'in_appcontent_subpage': False, 'extra_path': '/', - }) + }) url = page.get_absolute_url() if request.path != url: request._feincms_extra_context.update({ 'in_appcontent_subpage': True, - 'extra_path': re.sub('^' + re.escape(url.rstrip('/')), '', - request.path), - }) + 'extra_path': re.sub( + '^' + re.escape(url.rstrip('/')), + '', + request.path, + ), + }) def frontendediting_request_processor(page, request): diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index f854d8640..d75ef6c95 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -68,7 +68,7 @@ def feincms_frontend_editing(cms_obj, request): and request.COOKIES.get('frontend_editing') == 'True'): context = template.RequestContext(request, { "feincms_page": cms_obj, - }) + }) return render_to_string('admin/feincms/fe_tools.html', context) return u'' diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index c1f4e2da4..b67a1ae10 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -74,7 +74,7 @@ def __str__(self): self.size, '.', format, - ]) + ]) if not storage.exists(miniature): generate = True @@ -111,7 +111,8 @@ def generate(self, storage, original, size, miniature): buf = BytesIO() if image.mode not in ('RGBA', 'RGB', 'L'): image = image.convert('RGBA') - image.save(buf, + image.save( + buf, format if format.lower() in ('jpg', 'jpeg', 'png') else 'jpeg', quality=90) raw_data = buf.getvalue() diff --git a/feincms/translations.py b/feincms/translations.py index 1018c2d4d..140b6a128 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -112,7 +112,7 @@ def _transform(qs): candidates = list( instance_dict.values() - )[0].translations.model._default_manager.all() + )[0].translations.model._default_manager.all() if instance_dict: _process(candidates, instance_dict, lang_, 'iexact') @@ -137,12 +137,13 @@ def _found(instance_dict, candidate): del instance_dict[candidate.parent_id] def _process(candidates, instance_dict, lang_, op_): - for candidate in candidates.filter( - Q(parent__pk__in=instance_dict.keys()), - Q(**{'language_code__' + op_: lang_}) - | Q(**{'language_code__' + op_: short_language_code(lang_)}) - ).order_by('-language_code'): + candidates = candidates.filter( + Q(parent__pk__in=instance_dict.keys()), + Q(**{'language_code__' + op_: lang_}) + | Q(**{'language_code__' + op_: short_language_code(lang_)}) + ).order_by('-language_code') + for candidate in candidates: # The candidate's parent might already have a translation by now if candidate.parent_id in instance_dict: _found(instance_dict, candidate) @@ -176,14 +177,14 @@ def _get_translation_object(self, queryset, language_code): return queryset.filter( Q(language_code__iexact=language_code) | Q(language_code__iexact=short_language_code(language_code)) - ).order_by('-language_code')[0] + ).order_by('-language_code')[0] except IndexError: try: return queryset.filter( Q(language_code__istartswith=settings.LANGUAGE_CODE) | Q(language_code__istartswith=short_language_code( settings.LANGUAGE_CODE)) - ).order_by('-language_code')[0] + ).order_by('-language_code')[0] except IndexError: try: return queryset.all()[0] @@ -195,12 +196,16 @@ def get_translation_cache_key(self, language_code=None): can purge on-demand""" if not language_code: language_code = translation.get_language() - return (('FEINCMS:%d:XLATION:' % getattr(settings, 'SITE_ID', 0)) + - '-'.join(['%s' % s for s in ( + return ( + ('FEINCMS:%d:XLATION:' % getattr(settings, 'SITE_ID', 0)) + + '-'.join( + ['%s' % s for s in ( self._meta.db_table, self.id, language_code, - )])) + )] + ) + ) def get_translation(self, language_code=None): if not language_code: diff --git a/feincms/utils/html/tidy.py b/feincms/utils/html/tidy.py index 37b50550b..c5b97aaa7 100644 --- a/feincms/utils/html/tidy.py +++ b/feincms/utils/html/tidy.py @@ -67,7 +67,7 @@ def tidy_html(html): "fix-backslash": True, "indent": True, "output-xhtml": True, - } + } ) messages = filter(None, (l.strip() for l in messages.split("\n") if l)) diff --git a/setup.cfg b/setup.cfg index 1a738ac55..6bc2928b4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [flake8] exclude=venv,.tox,build,docs -ignore=E123,E128 +ignore=E128 [wheel] universal = 1 diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 1b3f8a870..22c26056a 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -24,15 +24,15 @@ 'regions': ( ('main', 'Main region'), ('sidebar', 'Sidebar', 'inherited'), - ), - }) + ), +}) Page.create_content_type(RawContent) Page.create_content_type(MediaFileContent, TYPE_CHOICES=( ('default', 'Default position'), - )) +)) Page.create_content_type(ImageContent, POSITION_CHOICES=( ('default', 'Default position'), - )) +)) def get_admin_fields(form, *args, **kwargs): @@ -44,28 +44,28 @@ def get_admin_fields(form, *args, **kwargs): help_text=_( 'Exclude everything other than the application\'s content' ' when rendering subpages.'), - ), + ), } Page.create_content_type(ApplicationContent, APPLICATIONS=( ('testapp.blog_urls', 'Blog', {'admin_fields': get_admin_fields}), ('whatever', 'Test Urls', {'urls': 'testapp.applicationcontent_urls'}), - )) +)) Entry.register_extensions( 'feincms.module.extensions.seo', 'feincms.module.extensions.translations', 'feincms.module.extensions.seo', 'feincms.module.extensions.ct_tracker', - ) +) Entry.register_regions( ('main', 'Main region'), - ) +) Entry.create_content_type(RawContent) Entry.create_content_type(ImageContent, POSITION_CHOICES=( ('default', 'Default position'), - )) +)) class BlogEntriesNavigationExtension(NavigationExtension): @@ -80,9 +80,10 @@ def children(self, page, **kwargs): for entry in Entry.objects.all(): yield PagePretender( title=entry.title, - url=reverse('testapp.blog_urls/blog_entry_detail', + url=reverse( + 'testapp.blog_urls/blog_entry_detail', kwargs={'object_id': entry.id}), - ) + ) Page.register_extensions( 'feincms.module.page.extensions.navigation', @@ -97,7 +98,7 @@ def children(self, page, **kwargs): 'feincms.module.page.extensions.navigation', 'feincms.module.page.extensions.symlinks', 'feincms.module.page.extensions.titles', - ) +) @python_2_unicode_compatible diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 1ca997416..8e377c8d8 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -38,7 +38,7 @@ def create_page(self, title='Test page', parent=None, **kwargs): 'site': self.site_1, 'in_navigation': False, 'active': False, - } + } defaults.update(kwargs) return Page.objects.create( title=title, diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index e69f0dc91..dfcf00dec 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -59,16 +59,16 @@ def setUp(self): 'regions': ( ('main', 'Main content area'), ('sidebar', 'Sidebar', 'inherited'), - ), - }, { + ), + }, { 'key': 'theother', 'title': 'This actually exists', 'path': 'base.html', 'regions': ( ('main', 'Main content area'), ('sidebar', 'Sidebar', 'inherited'), - ), - }) + ), + }) def login(self): self.assertTrue(self.client.login(username='test', password='test')) @@ -110,7 +110,7 @@ def create_page_through_admin(self, title='Test page', parent='', 'applicationcontent_set-TOTAL_FORMS': 0, 'applicationcontent_set-INITIAL_FORMS': 0, 'applicationcontent_set-MAX_NUM_FORMS': 10, - } + } dic.update(kwargs) return self.client.post('/admin/page/page/add/', dic) @@ -125,7 +125,7 @@ def create_page(self, title='Test page', parent=None, **kwargs): 'site': self.site_1, 'in_navigation': False, 'active': False, - } + } defaults.update(kwargs) return Page.objects.create( title=title, @@ -137,7 +137,7 @@ def create_default_page_set(self): self.create_page( 'Test child page', parent=self.create_page(), - ) + ) def is_published(self, url, should_be=True): try: @@ -250,7 +250,7 @@ def test_06_tree_editor_save(self): 'position': 'last-child', 'cut_item': '1', 'pasted_on': '5', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(Page.objects.get(pk=1).get_absolute_url(), '/page5/test-page/') @@ -265,32 +265,36 @@ def test_07_tree_editor_toggle_boolean(self): self.assertEqual(Page.objects.get(pk=1).in_navigation, False) self.login() - self.assertContains(self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'in_navigation', + self.assertContains( + self.client.post('/admin/page/page/', { + '__cmd': 'toggle_boolean', + 'item_id': 1, + 'attr': 'in_navigation', }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), r'checked=\"checked\"') self.assertEqual(Page.objects.get(pk=1).in_navigation, True) - self.assertNotContains(self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'in_navigation', + self.assertNotContains( + self.client.post('/admin/page/page/', { + '__cmd': 'toggle_boolean', + 'item_id': 1, + 'attr': 'in_navigation', }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), 'checked="checked"') self.assertEqual(Page.objects.get(pk=1).in_navigation, False) - self.assertTrue(isinstance(self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'notexists', + self.assertTrue(isinstance( + self.client.post('/admin/page/page/', { + '__cmd': 'toggle_boolean', + 'item_id': 1, + 'attr': 'notexists', }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), HttpResponseBadRequest)) def test_07_tree_editor_invalid_ajax(self): self.login() - self.assertContains(self.client.post('/admin/page/page/', { - '__cmd': 'notexists', + self.assertContains( + self.client.post('/admin/page/page/', { + '__cmd': 'notexists', }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), 'Oops. AJAX request not understood.', status_code=400) @@ -378,7 +382,7 @@ def create_page_through_admincontent(self, page, **kwargs): 'applicationcontent_set-TOTAL_FORMS': 1, 'applicationcontent_set-INITIAL_FORMS': 0, 'applicationcontent_set-MAX_NUM_FORMS': 10, - } + } data.update(kwargs) return self.client.post('/admin/page/page/%s/' % page.pk, data) @@ -651,7 +655,7 @@ def test_15_frontend_editing(self): 200) self.assertEqual(self.client.post('/admin/page/page/1|rawcontent|1/', { 'rawcontent-text': 'blablabla', - }).status_code, 200) + }).status_code, 200) self.assertEqual(page.content.main[0].render(), 'blablabla') self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') @@ -673,9 +677,9 @@ def test_15_b_client_frontend_editing(self): page.save() # FEINCMS_FRONTEND_EDITING is False by default - response = self.client.get(page.get_absolute_url() + - '?frontend_editing=1', - follow=True) + response = self.client.get( + page.get_absolute_url() + '?frontend_editing=1', + follow=True) self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) self.assertNotIn('frontend_editing', self.client.cookies) @@ -700,9 +704,9 @@ def test_15_b_client_frontend_editing(self): # anonymous user cannot front edit self.client.logout() - response = self.client.get(page.get_absolute_url() + - '?frontend_editing=1', - follow=True) + response = self.client.get( + page.get_absolute_url() + '?frontend_editing=1', + follow=True) self.assertRedirects(response, page.get_absolute_url()) self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) @@ -721,14 +725,15 @@ def test_17_page_template_tags(self): page2.in_navigation = True page2.save() - page3 = Page.objects.create(parent=page2, - title='page3', - slug='page3', - language='en', - active=True, - in_navigation=True, - publication_date=datetime(2001, 1, 1), - ) + page3 = Page.objects.create( + parent=page2, + title='page3', + slug='page3', + language='en', + active=True, + in_navigation=True, + publication_date=datetime(2001, 1, 1), + ) # reload these two, their mptt attributes have changed page1 = Page.objects.get(pk=1) @@ -1215,7 +1220,7 @@ def test_22_contactform(self): 'email': 'another@example.com', 'subject': 'This is a test. Please calm down', 'content': 'Hell on earth.', - }) + }) self.assertEqual(len(mail.outbox), 1) self.assertEqual( @@ -1457,7 +1462,7 @@ def test_28_applicationcontent_reverse(self): settings.TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), 'templates'), - ) + ) self.client.get(page_de_1.get_absolute_url()) self.assertEqual( app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), @@ -1512,7 +1517,7 @@ def test_29_medialibrary_admin(self): 'translations-TOTAL_FORMS': 0, 'translations-INITIAL_FORMS': 0, 'translations-MAX_NUM_FORMS': 10, - }) + }) self.assertRedirects(response, '/admin/medialibrary/mediafile/') self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index e06951b76..441171394 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -42,10 +42,14 @@ def test_region(self): # Creation should not fail r = Region('region', 'region title') - t = Template('base template', 'base.html', ( - ('region', 'region title'), - Region('region2', 'region2 title'), - )) + t = Template( + 'base template', + 'base.html', + ( + ('region', 'region title'), + Region('region2', 'region2 title'), + ), + ) # I'm not sure whether this test tests anything at all self.assertEqual(r.key, t.regions[0].key) @@ -96,8 +100,9 @@ class ExampleCMSBase(Base): class ExampleCMSBase2(Base): pass -ExampleCMSBase2.register_regions(('region', 'region title'), - ('region2', 'region2 title')) +ExampleCMSBase2.register_regions( + ('region', 'region title'), + ('region2', 'region2 title')) Page.create_content_type(ContactFormContent, form=ContactForm) Page.create_content_type(FileContent) From 64519d8e4f458c244ab4491502786b0f88531d27 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 08:45:14 +0100 Subject: [PATCH 0875/1590] Decouple feincms_nav and siblings_along_path_to from the Page model Refs #487. --- .../page/templatetags/feincms_page_tags.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index f49124fc8..03df87330 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -8,9 +8,11 @@ from django import template from django.conf import settings +from django.db.models.loading import get_model from django.http import HttpRequest -from feincms.module.page.models import BasePage, Page +from feincms import settings as feincms_settings +from feincms.module.page.models import BasePage from feincms.utils.templatetags import (SimpleNodeWithVarAndArgs, do_simple_node_with_var_and_args_helper, SimpleAssignmentNodeWithVarAndArgs, @@ -22,6 +24,10 @@ register = template.Library() +def _get_page_model(): + return get_model(*feincms_settings.FEINCMS_DEFAULT_PAGE_MODEL.split('.')) + + # ------------------------------------------------------------------------ # TODO: Belongs in some utility module def format_exception(e): @@ -36,12 +42,13 @@ def feincms_nav(context, feincms_page, level=1, depth=1): Saves a list of pages into the given context variable. """ + page_class = _get_page_model() + if isinstance(feincms_page, HttpRequest): try: - # warning: explicit Page reference here - feincms_page = Page.objects.for_request( + feincms_page = page_class.objects.for_request( feincms_page, best_match=True) - except Page.DoesNotExist: + except page_class.DoesNotExist: return [] mptt_opts = feincms_page._mptt_meta @@ -78,7 +85,7 @@ def feincms_nav(context, feincms_page, level=1, depth=1): # (or even deeper in the tree). If we would continue processing, # this would result in pages from different subtrees being # returned directly adjacent to each other. - queryset = Page.objects.none() + queryset = page_class.objects.none() if parent: if getattr(parent, 'navigation_extension', None): @@ -451,7 +458,9 @@ def siblings_along_path_to(page_list, page2): # Happens when we sit on a page outside the navigation tree so # fake an active root page to avoid a get_ancestors() db call # which would only give us a non-navigation root page anyway. - p = Page( + page_class = _get_page_model() + + p = page_class( title="dummy", tree_id=-1, parent_id=None, From 13599a54fd24c79fc2e32b91cbe0590ee058d828 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 08:45:50 +0100 Subject: [PATCH 0876/1590] Duck typing in feincms_breadcrumbs --- feincms/module/page/templatetags/feincms_page_tags.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 03df87330..f4850158c 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -12,7 +12,6 @@ from django.http import HttpRequest from feincms import settings as feincms_settings -from feincms.module.page.models import BasePage from feincms.utils.templatetags import (SimpleNodeWithVarAndArgs, do_simple_node_with_var_and_args_helper, SimpleAssignmentNodeWithVarAndArgs, @@ -336,10 +335,6 @@ def feincms_breadcrumbs(page, include_self=True): {% feincms_breadcrumbs feincms_page %} """ - if not page or not isinstance(page, BasePage): - raise ValueError( - "feincms_breadcrumbs must be called with a valid Page object") - ancs = page.get_ancestors() bc = [(anc.get_absolute_url(), anc.short_title()) for anc in ancs] From 87efc58393cef4c42a0403ef18d49da1176002c0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 14:34:28 +0100 Subject: [PATCH 0877/1590] Import the improved queryset_transform.py file from Towel --- feincms/utils/queryset_transform.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 368e11b93..70d33c3d5 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -10,7 +10,7 @@ This allows you to build optimisations like "fetch all tags for these 10 rows" while still benefiting from Django's lazy QuerySet evaluation. -For example: +For example:: def lookup_tags(item_qs): item_pks = [item.pk for item in item_qs] @@ -33,7 +33,7 @@ def lookup_tags(item_qs): for item in qs: print item, item.fetched_tags -Prints: +Prints:: Winter comes to Ogglesbrook [<sledging>, <snow>, <winter>, <skating>] Summer now [<skating>, <sunny>] @@ -94,9 +94,9 @@ def _clone(self, klass=None, setup=False, **kw): c._transform_fns = self._transform_fns[:] return c - def transform(self, fn): + def transform(self, *fn): c = self._clone() - c._transform_fns.append(fn) + c._transform_fns.extend(fn) return c def iterator(self): @@ -109,6 +109,16 @@ def iterator(self): return result_iter -class TransformManager(models.Manager): - def get_query_set(self): - return TransformQuerySet(self.model, using=self._db) +if hasattr(models.Manager, 'from_queryset'): + TransformManager = models.Manager.from_queryset(TransformQuerySet) + +else: + class TransformManager(models.Manager): + def get_queryset(self): + return TransformQuerySet(self.model, using=self._db) + + def get_query_set(self): + return TransformQuerySet(self.model, using=self._db) + + def transform(self, *fn): + return self.get_query_set().transform(*fn) From 88062bb6599f14acffbcbfd01c5b72f37caf36b3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 14:53:03 +0100 Subject: [PATCH 0878/1590] The page manager can be a tree manager in its own right --- feincms/module/page/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 91e66dd89..8fd72e6d4 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -14,7 +14,7 @@ from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ -from mptt.models import MPTTModel +from mptt.models import MPTTModel, TreeManager from feincms import settings from feincms.management.checker import check_database_schema @@ -31,7 +31,7 @@ # ------------------------------------------------------------------------ -class BasePageManager(models.Manager, ActiveAwareContentManagerMixin): +class BasePageManager(ActiveAwareContentManagerMixin, TreeManager): """ The page manager. Only adds new methods, does not modify standard Django manager behavior in any way. From 1d84e81066efbe4db1c0373bb61ad3aabd8cc796 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 17:10:30 +0100 Subject: [PATCH 0879/1590] Add a comment regarding __subclasses__ --- feincms/module/page/extensions/navigation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index a3085b942..591fe0071 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -19,6 +19,8 @@ class TypeRegistryMetaClass(type): """ You can access the list of subclasses as <BaseClass>.types + + TODO use NavigationExtension.__subclasses__() instead? """ def __init__(cls, name, bases, attrs): From c6b8c47c127961e85ccebe1f59d43c5b209454d7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 17:15:13 +0100 Subject: [PATCH 0880/1590] E128-clean example --- docs/releases/1.9.rst | 3 +-- example/blog_urls.py | 3 ++- example/manage.py | 4 ++-- example/models.py | 43 +++++++++++++++++++++++++++---------------- example/settings.py | 3 ++- example/urls.py | 7 ++++--- setup.cfg | 1 - 7 files changed, 38 insertions(+), 26 deletions(-) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index e31f7a308..19909ac04 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -55,8 +55,7 @@ Notable features and improvements * The diff between 1.8 and 1.9 is large -- most of it because of coding style cleanups. `flake8 <https://pypi.python.org/pypi/flake8>`_ runs should not - show any warnings. The only error code we'll ignore for some time is - ``E128``. + show any warnings. Bugfixes diff --git a/example/blog_urls.py b/example/blog_urls.py index 70932bbd2..9aae16176 100644 --- a/example/blog_urls.py +++ b/example/blog_urls.py @@ -4,7 +4,8 @@ from feincms.module.blog.models import Entry -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'^(?P<pk>\d+)/', generic.DetailView.as_view( queryset=Entry.objects.all(), ), name='blog_entry_detail'), diff --git a/example/manage.py b/example/manage.py index c778f2aac..729887ecd 100755 --- a/example/manage.py +++ b/example/manage.py @@ -2,8 +2,8 @@ import os import sys -sys.path.insert(0, - os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +sys.path.insert( + 0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings') diff --git a/example/models.py b/example/models.py index 774c7c2bb..758a0d125 100644 --- a/example/models.py +++ b/example/models.py @@ -12,8 +12,8 @@ from feincms.content.image.models import ImageContent from feincms.content.medialibrary.models import MediaFileContent from feincms.content.application.models import ApplicationContent -from feincms.module.page.extensions.navigation import (NavigationExtension, - PagePretender) +from feincms.module.page.extensions.navigation import ( + NavigationExtension, PagePretender) from feincms.content.application.models import app_reverse @@ -27,12 +27,18 @@ ), }) Page.create_content_type(RawContent) -Page.create_content_type(MediaFileContent, TYPE_CHOICES=( - ('default', 'Default position'), -)) -Page.create_content_type(ImageContent, POSITION_CHOICES=( - ('default', 'Default position'), -)) +Page.create_content_type( + MediaFileContent, + TYPE_CHOICES=( + ('default', 'Default position'), + ), +) +Page.create_content_type( + ImageContent, + POSITION_CHOICES=( + ('default', 'Default position'), + ), +) def get_admin_fields(form, *args, **kwargs): @@ -41,7 +47,8 @@ def get_admin_fields(form, *args, **kwargs): label=capfirst(_('exclusive subpages')), required=False, initial=form.instance.parameters.get('exclusive_subpages', False), - help_text=_('Exclude everything other than the application\'s' + help_text=_( + 'Exclude everything other than the application\'s' ' content when rendering subpages.'), ), } @@ -59,9 +66,12 @@ def get_admin_fields(form, *args, **kwargs): ('main', 'Main region'), ) Entry.create_content_type(RawContent) -Entry.create_content_type(ImageContent, POSITION_CHOICES=( - ('default', 'Default position'), -)) +Entry.create_content_type( + ImageContent, + POSITION_CHOICES=( + ('default', 'Default position'), + ) +) class BlogEntriesNavigationExtension(NavigationExtension): @@ -91,8 +101,8 @@ def children(self, page, **kwargs): class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() - parent = models.ForeignKey('self', blank=True, null=True, - related_name='children') + parent = models.ForeignKey( + 'self', blank=True, null=True, related_name='children') class Meta: ordering = ['tree_id', 'lft'] @@ -104,6 +114,7 @@ def __str__(self): # add m2m field to entry so it shows up in entry admin -Entry.add_to_class('categories', models.ManyToManyField(Category, - blank=True, null=True)) +Entry.add_to_class( + 'categories', + models.ManyToManyField(Category, blank=True, null=True)) EntryAdmin.list_filter += ('categories',) diff --git a/example/settings.py b/example/settings.py index 4f8ede3d5..b1f2d9c2b 100644 --- a/example/settings.py +++ b/example/settings.py @@ -89,6 +89,7 @@ from feincms.content.application.models import app_reverse ABSOLUTE_URL_OVERRIDES = { - 'blog.entry': lambda entry: app_reverse('blog_entry_detail', 'blog_urls', + 'blog.entry': lambda entry: app_reverse( + 'blog_entry_detail', 'blog_urls', args=(entry.id,)), } diff --git a/example/urls.py b/example/urls.py index 1347b39b8..5cba5b068 100644 --- a/example/urls.py +++ b/example/urls.py @@ -6,10 +6,11 @@ admin.autodiscover() -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'^admin/', include(admin.site.urls)), - url(r'^media/(?P<path>.*)$', 'django.views.static.serve', - {'document_root': os.path.join(os.path.dirname(__file__), 'media/')}), + url(r'^media/(?P<path>.*)$', 'django.views.static.serve', { + 'document_root': os.path.join(os.path.dirname(__file__), 'media/')}), url(r'', include('feincms.contrib.preview.urls')), url(r'', include('feincms.urls')) ) + staticfiles_urlpatterns() diff --git a/setup.cfg b/setup.cfg index 6bc2928b4..e0f9c91ef 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,5 @@ [flake8] exclude=venv,.tox,build,docs -ignore=E128 [wheel] universal = 1 From 76f2c79bda7d30405362a9aeb27a4dbee3e5b1c7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 17:21:42 +0100 Subject: [PATCH 0881/1590] Consistency is good. Start removing E128 warnings. --- feincms/__init__.py | 8 +++--- feincms/admin/filterspecs.py | 14 ++++++----- feincms/admin/item_editor.py | 11 +++++--- feincms/admin/tree_editor.py | 39 +++++++++++++++------------- feincms/models.py | 49 ++++++++++++++++++++++-------------- feincms/shortcuts.py | 4 ++- feincms/translations.py | 15 +++++++---- feincms/views/cbv/urls.py | 4 ++- 8 files changed, 88 insertions(+), 56 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index e9670fdeb..7ba632a84 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -11,8 +11,9 @@ def _load_settings(self): if not key.startswith('FEINCMS_'): continue - setattr(self, key, getattr(django_settings, key, - getattr(default_settings, key))) + value = getattr(default_settings, key) + value = getattr(django_settings, key, value) + setattr(self, key, value) def __getattr__(self, attr): self._load_settings() @@ -52,7 +53,8 @@ def ensure_completely_loaded(force=False): # don't miss out. from django.db.models import loading for model in loading.get_models(): - for cache_name in ('_field_cache', '_field_name_cache', '_m2m_cache', + for cache_name in ( + '_field_cache', '_field_name_cache', '_m2m_cache', '_related_objects_cache', '_related_many_to_many_cache', '_name_map'): try: diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index f5514aa55..fda501965 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -4,8 +4,8 @@ # Authors: Marinho Brandao <marinho at gmail.com> # Guilherme M. Gondim (semente) <semente at taurinus.org> -from django.contrib.admin.filters import (FieldListFilter, - ChoicesFieldListFilter) +from django.contrib.admin.filters import ( + FieldListFilter, ChoicesFieldListFilter) from django.utils import six from django.utils.encoding import smart_text from django.utils.safestring import mark_safe @@ -25,7 +25,7 @@ class ParentFieldListFilter(ChoicesFieldListFilter): """ def __init__(self, f, request, params, model, model_admin, - field_path=None): + field_path=None): super(ParentFieldListFilter, self).__init__( f, request, params, model, model_admin, field_path) @@ -64,7 +64,7 @@ class CategoryFieldListFilter(ChoicesFieldListFilter): """ def __init__(self, f, request, params, model, model_admin, - field_path=None): + field_path=None): super(CategoryFieldListFilter, self).__init__( f, request, params, model, model_admin, field_path) @@ -95,9 +95,11 @@ def title(self): return _('Category') -FieldListFilter.register(lambda f: getattr(f, 'parent_filter', False), +FieldListFilter.register( + lambda f: getattr(f, 'parent_filter', False), ParentFieldListFilter, take_priority=True) -FieldListFilter.register(lambda f: getattr(f, 'category_filter', False), +FieldListFilter.register( + lambda f: getattr(f, 'category_filter', False), CategoryFieldListFilter, take_priority=True) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 9469bd538..da0b7e75d 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -127,7 +127,7 @@ def get_feincms_inlines(self, model, request): return inlines def _frontend_editing_view(self, request, cms_id, content_type, - content_id): + content_id): """ This view is used strictly for frontend editing -- it is not used inside the standard administration interface. @@ -146,7 +146,8 @@ def _frontend_editing_view(self, request, cms_id, content_type, form_class_base = getattr( model_cls, 'feincms_item_editor_form', ItemEditorForm) - ModelForm = modelform_factory(model_cls, + ModelForm = modelform_factory( + model_cls, exclude=('parent', 'region', 'ordering'), form=form_class_base, formfield_callback=curry( @@ -190,7 +191,9 @@ def _frontend_editing_view(self, request, cms_id, content_type, 'media': self.media, }) - return render_to_response('admin/feincms/fe_editor.html', context, + return render_to_response( + 'admin/feincms/fe_editor.html', + context, context_instance=template.RequestContext(request)) def get_content_type_map(self, request): @@ -340,7 +343,7 @@ def get_fieldsets(self, request, obj=None): recover_form_template = "admin/feincms/recover_form.html" def render_revision_form(self, request, obj, version, context, - revert=False, recover=False): + revert=False, recover=False): context.update(self.get_extra_context(request)) return super(ItemEditor, self).render_revision_form( request, obj, version, context, revert, recover) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 46daaafed..7d3ae0e6c 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -10,7 +10,8 @@ from django.contrib.admin.actions import delete_selected from django.contrib.staticfiles.templatetags.staticfiles import static from django.db.models import Q -from django.http import (HttpResponse, HttpResponseBadRequest, +from django.http import ( + HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound, HttpResponseServerError) from django.utils.html import escape from django.utils.safestring import mark_safe @@ -41,8 +42,8 @@ def django_boolean_icon(field_val, alt_text=None, title=None): else: title = '' icon_url = static('feincms/img/icon-%s.gif' % BOOLEAN_MAPPING[field_val]) - return mark_safe(u'<img src="%s" alt="%s" %s/>' % - (icon_url, alt_text, title)) + return mark_safe( + u'<img src="%s" alt="%s" %s/>' % (icon_url, alt_text, title)) def _build_tree_structure(queryset): @@ -164,15 +165,17 @@ def get_query_set(self, *args, **kwargs): def get_results(self, request): mptt_opts = self.model._mptt_meta if settings.FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS: - clauses = [Q(**{mptt_opts.tree_id_attr: tree_id, - mptt_opts.left_attr + '__lte': lft, - mptt_opts.right_attr + '__gte': rght, - }) - for lft, rght, tree_id in self.query_set.values_list( - mptt_opts.left_attr, - mptt_opts.right_attr, - mptt_opts.tree_id_attr, - )] + clauses = [ + Q(**{ + mptt_opts.tree_id_attr: tree_id, + mptt_opts.left_attr + '__lte': lft, + mptt_opts.right_attr + '__gte': rght, + }) for lft, rght, tree_id in self.query_set.values_list( + mptt_opts.left_attr, + mptt_opts.right_attr, + mptt_opts.tree_id_attr, + ) + ] # We could optimise a bit here by explicitely filtering out # any clauses that are for parents of nodes included in the # queryset anyway. (ie: drop all clauses that refer to a node @@ -364,7 +367,8 @@ def _toggle_boolean(self, request): _("You do not have permission to modify this object")) new_state = not getattr(obj, attr) - logger.info("Toggle %s on #%d %s to %s by \"%s\"", + logger.info( + "Toggle %s on #%d %s to %s by \"%s\"", attr, obj.pk, obj, "on" if new_state else "off", request.user) try: @@ -493,9 +497,9 @@ def _move_node(self, request): for item in queryset.filter(id__in=(cut_item.pk, pasted_on.pk)): item.save() - self.message_user(request, - ugettext('%s has been moved to a new position.') % - cut_item) + self.message_user( + request, + ugettext('%s has been moved to a new position.') % cut_item) return HttpResponse('OK') self.message_user(request, _('Did not understand moving instruction.')) @@ -530,7 +534,8 @@ def delete_selected_tree(self, modeladmin, request, queryset): logger.warning( "Denied delete request by \"%s\" for object #%s", request.user, obj.id) - self.message_user(request, + self.message_user( + request, _("Successfully deleted %(count)d items.") % {"count": n}) # Return None to display the change list page again return None diff --git a/feincms/models.py b/feincms/models.py index 579c0b7fb..bef21510a 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -50,8 +50,10 @@ def content_types(self): of (content type key, beautified content type name) tuples """ - return [(ct.__name__.lower(), ct._meta.verbose_name) - for ct in self._content_types] + return [ + (ct.__name__.lower(), ct._meta.verbose_name) + for ct in self._content_types + ] @python_2_unicode_compatible @@ -62,7 +64,7 @@ class Template(object): """ def __init__(self, title, path, regions, key=None, preview_image=None, - **kwargs): + **kwargs): # The key is what will be stored in the database. If key is undefined # use the template path as fallback. if not key: @@ -174,8 +176,10 @@ def _fetch_content_type_count_helper(self, pk, regions=None): tmpl.append('GROUP BY region') tmpl = u' '.join(tmpl) - sql = ' UNION '.join([tmpl % (idx, cls._meta.db_table, pk) - for idx, cls in enumerate(self.item._feincms_content_types)]) + sql = ' UNION '.join([ + tmpl % (idx, cls._meta.db_table, pk) + for idx, cls in enumerate(self.item._feincms_content_types) + ]) sql = 'SELECT * FROM ( ' + sql + ' ) AS ct ORDER BY ct_idx' cursor = connections[self.db].cursor() @@ -202,16 +206,19 @@ def _popuplate_content_type_caches(self, types): ).append((region, pk)) # Resolve abstract to concrete content types - content_types = (cls for cls in self.item._feincms_content_types - if issubclass(cls, tuple(types))) + content_types = ( + cls for cls in self.item._feincms_content_types + if issubclass(cls, tuple(types)) + ) for cls in content_types: counts = counts_by_type.get(cls) if cls not in self._cache['cts']: if counts: - self._cache['cts'][cls] = list(cls.get_queryset( - reduce(operator.or_, ( - Q(region=r[0], parent=r[1]) for r in counts)))) + self._cache['cts'][cls] = list(cls.get_queryset(reduce( + operator.or_, + (Q(region=r[0], parent=r[1]) for r in counts) + ))) else: self._cache['cts'][cls] = [] @@ -578,7 +585,7 @@ def get_queryset(cls, filter_args): @classmethod def create_content_type(cls, model, regions=None, class_name=None, - **kwargs): + **kwargs): """ This is the method you'll use to create concrete content types. @@ -654,7 +661,8 @@ def create_content_type(cls, model, regions=None, class_name=None, RuntimeWarning) if not model._meta.abstract: - raise ImproperlyConfigured('Cannot create content type from' + raise ImproperlyConfigured( + 'Cannot create content type from' ' non-abstract model (yet).') if not hasattr(cls, '_feincms_content_model'): @@ -696,8 +704,8 @@ class Meta(feincms_content_base.Meta): # content types can be limited to a subset of regions if not regions: - regions = set([region.key for region - in cls._feincms_all_regions]) + regions = set([ + region.key for region in cls._feincms_all_regions]) for region in cls._feincms_all_regions: if region.key in regions: @@ -776,7 +784,8 @@ def _needs_templates(cls): # helper which can be used to ensure that either register_regions # or register_templates has been executed before proceeding if not hasattr(cls, 'template'): - raise ImproperlyConfigured('You need to register at least one' + raise ImproperlyConfigured( + 'You need to register at least one' ' template or one region on %s.' % cls.__name__) @classmethod @@ -785,9 +794,11 @@ def _needs_content_types(cls): # Check whether any content types have been created for this base # class - if (not hasattr(cls, '_feincms_content_types') + if ( + not hasattr(cls, '_feincms_content_types') or not cls._feincms_content_types): - raise ImproperlyConfigured('You need to create at least one' + raise ImproperlyConfigured( + 'You need to create at least one' ' content type for the %s model.' % cls.__name__) def copy_content_from(self, obj): @@ -799,8 +810,8 @@ def copy_content_from(self, obj): for cls in self._feincms_content_types: for content in cls.objects.filter(parent=obj): - new = copy_model_instance(content, - exclude=('id', 'parent')) + new = copy_model_instance( + content, exclude=('id', 'parent')) new.parent = self new.save() diff --git a/feincms/shortcuts.py b/feincms/shortcuts.py index be63353ac..367141159 100644 --- a/feincms/shortcuts.py +++ b/feincms/shortcuts.py @@ -12,5 +12,7 @@ def render_to_response_best_match(request, template_name, dictionary=None): dictionary = dictionary or {} dictionary['feincms_page'] = Page.objects.best_match_for_request(request) - return render_to_response(template_name, dictionary, + return render_to_response( + template_name, + dictionary, context_instance=RequestContext(request)) diff --git a/feincms/translations.py b/feincms/translations.py index 140b6a128..537256b68 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -117,8 +117,12 @@ def _transform(qs): if instance_dict: _process(candidates, instance_dict, lang_, 'iexact') if instance_dict: - _process(candidates, instance_dict, settings.LANGUAGE_CODE, - 'istartswith') + _process( + candidates, + instance_dict, + settings.LANGUAGE_CODE, + 'istartswith', + ) if instance_dict: for candidate in candidates.filter( parent__pk__in=instance_dict.keys()): @@ -272,9 +276,10 @@ def Translation(model): class Inner(models.Model): parent = models.ForeignKey(model, related_name='translations') - language_code = models.CharField(_('language'), max_length=10, - choices=settings.LANGUAGES, default=settings.LANGUAGES[0][0], - editable=len(settings.LANGUAGES) > 1) + language_code = models.CharField( + _('language'), max_length=10, + choices=settings.LANGUAGES, default=settings.LANGUAGES[0][0], + editable=len(settings.LANGUAGES) > 1) class Meta: unique_together = ('parent', 'language_code') diff --git a/feincms/views/cbv/urls.py b/feincms/views/cbv/urls.py index 91ab4156a..0e6465080 100644 --- a/feincms/views/cbv/urls.py +++ b/feincms/views/cbv/urls.py @@ -3,9 +3,11 @@ from django.conf.urls import patterns, url from .views import Handler + handler = Handler.as_view() -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'^$', handler, name='feincms_home'), url(r'^(.*)/$', handler, name='feincms_handler'), ) From d9b27ad684bfbaf66720846a7ca141d38f20fefe Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 17:31:46 +0100 Subject: [PATCH 0882/1590] -E128 on contents and management --- feincms/content/application/models.py | 24 +++++++++++++++--------- feincms/content/comments/models.py | 3 ++- feincms/content/contactform/models.py | 3 ++- feincms/content/medialibrary/models.py | 14 +++++++++++--- feincms/content/richtext/models.py | 6 ++++-- feincms/content/rss/models.py | 18 ++++++++++-------- feincms/content/section/models.py | 9 ++++++--- feincms/content/template/models.py | 7 ++++--- feincms/content/video/models.py | 12 ++++++++---- feincms/contrib/preview/urls.py | 3 ++- feincms/contrib/richtext.py | 3 ++- feincms/contrib/tagging.py | 8 ++++---- feincms/management/checker.py | 8 +++++--- 13 files changed, 75 insertions(+), 43 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 26e07a2ff..38a9d9d74 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -9,8 +9,8 @@ from django.conf import settings from django.core.cache import cache -from django.core.urlresolvers import (Resolver404, resolve, reverse, - NoReverseMatch) +from django.core.urlresolvers import ( + Resolver404, resolve, reverse, NoReverseMatch) from django.db import models from django.db.models import signals from django.http import HttpResponse @@ -38,7 +38,7 @@ def cycle_app_reverse_cache(*args, **kwargs): def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, - *vargs, **vkwargs): + *vargs, **vkwargs): """ Reverse URLs from application contents @@ -96,7 +96,8 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, if url_prefix: # vargs and vkwargs are used to send through additional parameters # which are uninteresting to us (such as current_app) - return reverse(viewname, + return reverse( + viewname, url_prefix[0], args=args, kwargs=kwargs, @@ -171,7 +172,8 @@ def initialize_type(cls, APPLICATIONS): "config": app_conf } - cls.add_to_class('urlconf_path', + cls.add_to_class( + 'urlconf_path', models.CharField(_('application'), max_length=100, choices=[ (c['urls'], c['name']) for c in cls.ALL_APPS_CONFIG.values()]) ) @@ -218,8 +220,9 @@ def save(self, commit=True, *args, **kwargs): m = super(ApplicationContentItemEditorForm, self).save( commit=False, *args, **kwargs) - m.parameters = dict((k, self.cleaned_data[k]) for k - in self.custom_fields if k in self.cleaned_data) + m.parameters = dict( + (k, self.cleaned_data[k]) + for k in self.custom_fields if k in self.cleaned_data) if commit: m.save(**kwargs) @@ -274,8 +277,11 @@ def process(self, request, **kw): # Save the application configuration for reuse elsewhere request._feincms_extra_context.update({ - 'app_config': dict(self.app_config, - urlconf_path=self.urlconf_path)}) + 'app_config': dict( + self.app_config, + urlconf_path=self.urlconf_path, + ), + }) view_wrapper = self.app_config.get("view_wrapper", None) if view_wrapper: diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index a9907e954..66335c8dd 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -25,7 +25,8 @@ # ------------------------------------------------------------------------ class CommentsContent(models.Model): - comments_enabled = models.BooleanField(_('enabled'), default=True, + comments_enabled = models.BooleanField( + _('enabled'), default=True, help_text=_('New comments may be added')) class Meta: diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index 1e60802d9..d669f010b 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -19,7 +19,8 @@ class ContactForm(forms.Form): email = forms.EmailField(label=_('email')) subject = forms.CharField(label=_('subject')) - content = forms.CharField(widget=forms.Textarea, required=False, + content = forms.CharField( + widget=forms.Textarea, required=False, label=_('content')) diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index f95ed4b77..396dd50a8 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -52,11 +52,19 @@ class Meta: @classmethod def initialize_type(cls, TYPE_CHOICES=None): if TYPE_CHOICES is None: - raise ImproperlyConfigured('You have to set TYPE_CHOICES when' + raise ImproperlyConfigured( + 'You have to set TYPE_CHOICES when' ' creating a %s' % cls.__name__) - cls.add_to_class('type', models.CharField(_('type'), - max_length=20, choices=TYPE_CHOICES, default=TYPE_CHOICES[0][0])) + cls.add_to_class( + 'type', + models.CharField( + _('type'), + max_length=20, + choices=TYPE_CHOICES, + default=TYPE_CHOICES[0][0], + ) + ) def render(self, **kwargs): ctx = {'content': self} diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 98ecdeacd..7f8bdc4b7 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -102,8 +102,10 @@ class Meta: verbose_name_plural = _('rich texts') def render(self, **kwargs): - return render_to_string('content/richtext/default.html', - {'content': self}, context_instance=kwargs.get('context')) + return render_to_string( + 'content/richtext/default.html', + {'content': self}, + context_instance=kwargs.get('context')) def save(self, *args, **kwargs): # TODO: Move this to the form? diff --git a/feincms/content/rss/models.py b/feincms/content/rss/models.py index 789d399e8..e7fcc3ff6 100644 --- a/feincms/content/rss/models.py +++ b/feincms/content/rss/models.py @@ -17,15 +17,17 @@ class RSSContent(models.Model): ``./manage.py update_rsscontent`` every couple of hours. """ - title = models.CharField(_('title'), max_length=50, - help_text=_('The rss field is updated several times a day.' + title = models.CharField( + _('title'), max_length=50, + help_text=_( + 'The rss field is updated several times a day.' ' A change in the title will only be visible on the home page' ' after the next feed update.')) link = models.URLField(_('link')) - rendered_content = models.TextField(_('pre-rendered content'), blank=True, - editable=False) - last_updated = models.DateTimeField(_('last updated'), - blank=True, null=True) + rendered_content = models.TextField( + _('pre-rendered content'), blank=True, editable=False) + last_updated = models.DateTimeField( + _('last updated'), blank=True, null=True) max_items = models.IntegerField(_('max. items'), default=5) class Meta: @@ -41,8 +43,8 @@ def cache_content(self, date_format=None, save=True): entries = feed['entries'][:self.max_items] if date_format: for entry in entries: - entry.updated = time.strftime(date_format, - entry.updated_parsed) + entry.updated = time.strftime( + date_format, entry.updated_parsed) self.rendered_content = render_to_string( 'content/rss/content.html', diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index a85304c3c..f9a26ed3e 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -32,7 +32,8 @@ class SectionContent(models.Model): title = models.CharField(_('title'), max_length=200, blank=True) richtext = RichTextField(_('text'), blank=True) - mediafile = MediaFileForeignKey(MediaFile, verbose_name=_('media file'), + mediafile = MediaFileForeignKey( + MediaFile, verbose_name=_('media file'), related_name='+', blank=True, null=True) class Meta: @@ -52,9 +53,11 @@ def initialize_type(cls, TYPE_CHOICES=None, cleanse=None): 'You need to set TYPE_CHOICES when creating a' ' %s' % cls.__name__) - cls.add_to_class('type', models.CharField(_('type'), + cls.add_to_class('type', models.CharField( + _('type'), max_length=10, choices=TYPE_CHOICES, - default=TYPE_CHOICES[0][0])) + default=TYPE_CHOICES[0][0] + )) if cleanse: cls.cleanse = cleanse diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 03163136d..31e9190ec 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -1,8 +1,8 @@ import os from django.db import models -from django.template.loader import (Context, Template, TemplateDoesNotExist, - find_template_loader) +from django.template.loader import ( + Context, Template, TemplateDoesNotExist, find_template_loader) from django.utils.translation import ugettext_lazy as _ @@ -53,7 +53,8 @@ class Meta: @classmethod def initialize_type(cls, TEMPLATE_LOADERS=DEFAULT_TEMPLATE_LOADERS): - cls.template_loaders = [find_template_loader(loader) + cls.template_loaders = [ + find_template_loader(loader) for loader in TEMPLATE_LOADERS if loader] cls.add_to_class('filename', models.CharField( diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index f5a1abe74..f84f6e161 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -28,8 +28,10 @@ class VideoContent(models.Model): }), ) - video = models.URLField(_('video link'), - help_text=_('This should be a link to a youtube or vimeo video,' + video = models.URLField( + _('video link'), + help_text=_( + 'This should be a link to a youtube or vimeo video,' ' i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0')) class Meta: @@ -64,5 +66,7 @@ def ctx_for_video(self, vurl): def render(self, **kwargs): context_instance = kwargs.get('context') ctx = self.ctx_for_video(self.video) - return render_to_string(self.get_templates(ctx['portal']), - ctx, context_instance=context_instance) + return render_to_string( + self.get_templates(ctx['portal']), + ctx, + context_instance=context_instance) diff --git a/feincms/contrib/preview/urls.py b/feincms/contrib/preview/urls.py index a957b5ca3..83bc5e4d8 100644 --- a/feincms/contrib/preview/urls.py +++ b/feincms/contrib/preview/urls.py @@ -3,7 +3,8 @@ from feincms.contrib.preview.views import PreviewHandler -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'^(.*)/_preview/(\d+)/$', PreviewHandler.as_view(), name='feincms_preview'), ) diff --git a/feincms/contrib/richtext.py b/feincms/contrib/richtext.py index 8aa41952a..89ad29f8a 100644 --- a/feincms/contrib/richtext.py +++ b/feincms/contrib/richtext.py @@ -29,7 +29,8 @@ def formfield(self, form_class=RichTextFormField, **kwargs): RichTextField_introspection_rule = ((RichTextField,), [], {},) - add_introspection_rules(rules=[RichTextField_introspection_rule], + add_introspection_rules( + rules=[RichTextField_introspection_rule], patterns=["^feincms\.contrib\.richtext"]) except ImportError: pass diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index d325508b8..e26cfef99 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -66,8 +66,8 @@ def formfield(self, **defaults): def _render(name, value, attrs=None, *args, **kwargs): value = parse_tag_input(value) - return type(widget).render(widget, name, value, attrs, - *args, **kwargs) + return type(widget).render( + widget, name, value, attrs, *args, **kwargs) widget.render = _render defaults['widget'] = widget choices = [( @@ -90,8 +90,8 @@ def pre_save_handler(sender, instance, **kwargs): # ------------------------------------------------------------------------ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, - select_field=False, auto_add_admin_field=True, - admin_list_display=True): + select_field=False, auto_add_admin_field=True, + admin_list_display=True): """ tag_model accepts a number of named parameters: diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 363dc40ab..fcecd139d 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -28,9 +28,11 @@ def _fn(sender, **kwargs): cursor = connection.cursor() - existing_columns = [row[0] for row in - connection.introspection.get_table_description( - cursor, cls._meta.db_table)] + existing_columns = [ + row[0] + for row in connection.introspection.get_table_description( + cursor, cls._meta.db_table) + ] missing_columns = [] From 2a3b9e6c4837bd633f9f5074b16362e89274d3d4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 17:39:33 +0100 Subject: [PATCH 0883/1590] -E128, only tests and template tags missing now --- feincms/module/blog/models.py | 10 +++-- feincms/module/extensions/datepublisher.py | 14 ++++--- feincms/module/extensions/translations.py | 14 ++++--- feincms/module/medialibrary/fields.py | 7 ++-- feincms/module/medialibrary/modeladmins.py | 10 +++-- feincms/module/medialibrary/models.py | 25 ++++++------ feincms/module/page/extensions/excerpt.py | 13 ++++--- feincms/module/page/extensions/sites.py | 7 ++-- feincms/module/page/extensions/titles.py | 6 ++- feincms/module/page/forms.py | 7 ++-- feincms/module/page/modeladmins.py | 8 ++-- feincms/module/page/models.py | 45 +++++++++++++--------- feincms/module/page/sitemap.py | 5 ++- 13 files changed, 102 insertions(+), 69 deletions(-) diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index 48e2bcb73..0662ee734 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -28,13 +28,15 @@ def published(self): @python_2_unicode_compatible class Entry(Base): published = models.BooleanField(_('published'), default=False) - title = models.CharField(_('title'), max_length=100, + title = models.CharField( + _('title'), max_length=100, help_text=_('This is used for the generated navigation too.')) slug = models.SlugField() - published_on = models.DateTimeField(_('published on'), - blank=True, null=True, - help_text=_('Will be set automatically once you tick the `published`' + published_on = models.DateTimeField( + _('published on'), blank=True, null=True, + help_text=_( + 'Will be set automatically once you tick the `published`' ' checkbox above.')) class Meta: diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 1d9cad8bc..a6f392297 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -49,8 +49,9 @@ def granular_now(n=None): """ if n is None: n = timezone.now() - return timezone.make_aware(datetime(n.year, n.month, n.day, n.hour, - (n.minute // 5) * 5), n.tzinfo) + return timezone.make_aware( + datetime(n.year, n.month, n.day, n.hour, (n.minute // 5) * 5), + n.tzinfo) # ------------------------------------------------------------------------ @@ -78,10 +79,13 @@ def datepublisher_response_processor(page, request, response): # ------------------------------------------------------------------------ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('publication_date', + self.model.add_to_class( + 'publication_date', models.DateTimeField(_('publication date'), default=granular_now)) - self.model.add_to_class('publication_end_date', - models.DateTimeField(_('publication end date'), + self.model.add_to_class( + 'publication_end_date', + models.DateTimeField( + _('publication end date'), blank=True, null=True, help_text=_( 'Leave empty if the entry should stay active forever.'))) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 4df7948f0..eda73162a 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -132,13 +132,17 @@ class Extension(extensions.Extension): def handle_model(self): cls = self.model - cls.add_to_class('language', models.CharField(_('language'), - max_length=10, - choices=django_settings.LANGUAGES, - default=django_settings.LANGUAGES[0][0])) + cls.add_to_class( + 'language', + models.CharField( + _('language'), + max_length=10, + choices=django_settings.LANGUAGES, + default=django_settings.LANGUAGES[0][0])) cls.add_to_class( 'translation_of', - models.ForeignKey('self', + models.ForeignKey( + 'self', blank=True, null=True, verbose_name=_('translation of'), related_name='translations', limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 1313d12a1..a8ec5aef2 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -62,8 +62,8 @@ class ContentWithMediaFile(models.Model): class feincms_item_editor_inline(FeinCMSInline): raw_id_fields = ('mediafile',) - mediafile = MediaFileForeignKey(MediaFile, verbose_name=_('media file'), - related_name='+') + mediafile = MediaFileForeignKey( + MediaFile, verbose_name=_('media file'), related_name='+') class Meta: abstract = True @@ -93,7 +93,8 @@ def render(self, name, value, attrs=None): try: from south.modelsinspector import add_introspection_rules - add_introspection_rules(rules=[((MediaFileForeignKey,), [], {},)], + add_introspection_rules( + rules=[((MediaFileForeignKey,), [], {},)], patterns=["^feincms\.module\.medialibrary\.fields"]) except ImportError: pass diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 21cc77037..2ac1fa25f 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -111,8 +111,8 @@ class MediaFileAdmin(ExtensionModelAdmin): save_on_top = True date_hierarchy = 'created' inlines = [admin_translationinline(MediaFileTranslation)] - list_display = ['admin_thumbnail', '__str__', 'file_info', - 'formatted_created'] + list_display = [ + 'admin_thumbnail', '__str__', 'file_info', 'formatted_created'] list_display_links = ['__str__'] list_filter = ['type', 'categories'] list_per_page = 25 @@ -124,10 +124,12 @@ def get_urls(self): from django.conf.urls import patterns, url urls = super(MediaFileAdmin, self).get_urls() - my_urls = patterns('', + my_urls = patterns( + '', url( r'^mediafile-bulk-upload/$', - self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, + self.admin_site.admin_view(MediaFileAdmin.bulk_upload), + {}, name='mediafile_bulk_upload', ), ) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index bae431a73..3f4f54221 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -17,8 +17,8 @@ from feincms import settings from feincms.models import ExtensionsMixin -from feincms.translations import (TranslatedObjectMixin, Translation, - TranslatedObjectManager) +from feincms.translations import ( + TranslatedObjectMixin, Translation, TranslatedObjectManager) from . import logger @@ -43,7 +43,8 @@ class Category(models.Model): """ title = models.CharField(_('title'), max_length=200) - parent = models.ForeignKey('self', blank=True, null=True, + parent = models.ForeignKey( + 'self', blank=True, null=True, related_name='children', limit_choices_to={'parent__isnull': True}, verbose_name=_('parent')) @@ -89,18 +90,20 @@ class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): mechanism. """ - file = models.FileField(_('file'), max_length=255, + file = models.FileField( + _('file'), max_length=255, upload_to=settings.FEINCMS_MEDIALIBRARY_UPLOAD_TO) - type = models.CharField(_('file type'), max_length=12, editable=False, + type = models.CharField( + _('file type'), max_length=12, editable=False, choices=()) - created = models.DateTimeField(_('created'), editable=False, - default=timezone.now) + created = models.DateTimeField( + _('created'), editable=False, default=timezone.now) copyright = models.CharField(_('copyright'), max_length=200, blank=True) - file_size = models.IntegerField(_("file size"), blank=True, null=True, - editable=False) + file_size = models.IntegerField( + _("file size"), blank=True, null=True, editable=False) - categories = models.ManyToManyField(Category, verbose_name=_('categories'), - blank=True, null=True) + categories = models.ManyToManyField( + Category, verbose_name=_('categories'), blank=True, null=True) categories.category_filter = True class Meta: diff --git a/feincms/module/page/extensions/excerpt.py b/feincms/module/page/extensions/excerpt.py index 5cc3be28d..e35d0266f 100644 --- a/feincms/module/page/extensions/excerpt.py +++ b/feincms/module/page/extensions/excerpt.py @@ -10,11 +10,14 @@ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('excerpt', models.TextField( - _('excerpt'), - blank=True, - help_text=_('Add a brief excerpt summarizing the content' - ' of this page.'))) + self.model.add_to_class( + 'excerpt', + models.TextField( + _('excerpt'), + blank=True, + help_text=_( + 'Add a brief excerpt summarizing the content' + ' of this page.'))) def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Excerpt'), { diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index 9083a7b1f..93e510c89 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -13,9 +13,10 @@ def current_site(queryset): class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('site', - models.ForeignKey(Site, verbose_name=_('Site'), - default=settings.SITE_ID)) + self.model.add_to_class( + 'site', + models.ForeignKey( + Site, verbose_name=_('Site'), default=settings.SITE_ID)) PageManager.add_to_active_filters(current_site, key='current_site') diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index e92f7000f..7cc5efa6e 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -16,14 +16,16 @@ def handle_model(self): self.model.add_to_class('_content_title', models.TextField( _('content title'), blank=True, - help_text=_('The first line is the main title, the following' + help_text=_( + 'The first line is the main title, the following' ' lines are subtitles.'))) self.model.add_to_class('_page_title', models.CharField( _('page title'), max_length=69, blank=True, - help_text=_('Page title for browser window. Same as title by' + help_text=_( + 'Page title for browser window. Same as title by' 'default. Must not be longer than 70 characters.'))) @monkeypatch_property(self.model) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 0609ba135..6bd8c5859 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -31,8 +31,8 @@ def label_for_value(self, value): model = get_model(matches['app_label'], matches['module_name']) try: instance = model._default_manager.get(pk=int(matches['pk'])) - return u' <strong>%s (%s)</strong>' % (instance, - instance.get_absolute_url()) + return u' <strong>%s (%s)</strong>' % ( + instance, instance.get_absolute_url()) except model.DoesNotExist: pass @@ -42,7 +42,8 @@ def label_for_value(self, value): # ------------------------------------------------------------------------ class PageAdminForm(MPTTAdminForm): - never_copy_fields = ('title', 'slug', 'parent', 'active', 'override_url', + never_copy_fields = ( + 'title', 'slug', 'parent', 'active', 'override_url', 'translation_of', '_content_title', '_page_title') @property diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 3c6caf105..8df776db9 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -41,16 +41,16 @@ class Media: }), (_('Other options'), { 'classes': ['collapse'], - 'fields': ['template_key', 'parent', 'override_url', - 'redirect_to'], + 'fields': [ + 'template_key', 'parent', 'override_url', 'redirect_to'], }), # <-- insertion point, extensions appear here, see insertion_index # above item_editor.FEINCMS_CONTENT_FIELDSET, ] readonly_fields = [] - list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', - 'template'] + list_display = [ + 'short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] list_filter = ['active', 'in_navigation', 'template_key', 'parent'] search_fields = ['title', 'slug'] prepopulated_fields = {'slug': ('title',)} diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 8fd72e6d4..11a7cd283 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -38,8 +38,8 @@ class BasePageManager(ActiveAwareContentManagerMixin, TreeManager): """ # The fields which should be excluded when creating a copy. - exclude_from_copy = ['id', 'tree_id', 'lft', 'rght', 'level', - 'redirect_to'] + exclude_from_copy = [ + 'id', 'tree_id', 'lft', 'rght', 'level', 'redirect_to'] def page_for_path(self, path, raise404=False): """ @@ -92,7 +92,8 @@ def best_match_for_path(self, path, raise404=False): if path: tokens = path.split('/') - paths += ['/%s/' % '/'.join(tokens[:i]) + paths += [ + '/%s/' % '/'.join(tokens[:i]) for i in range(1, len(tokens) + 1)] try: @@ -127,7 +128,7 @@ def toplevel_navigation(self): return self.in_navigation().filter(parent__isnull=True) def for_request(self, request, raise404=False, best_match=False, - path=None): + path=None): """ Return a page for the request @@ -145,11 +146,11 @@ def for_request(self, request, raise404=False, best_match=False, path = path or request.path_info or request.path if best_match: - request._feincms_page = self.best_match_for_path(path, - raise404=raise404) + request._feincms_page = self.best_match_for_path( + path, raise404=raise404) else: - request._feincms_page = self.page_for_path(path, - raise404=raise404) + request._feincms_page = self.page_for_path( + path, raise404=raise404) return request._feincms_page @@ -168,23 +169,29 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): # structure and navigation title = models.CharField(_('title'), max_length=200, help_text=_( 'This title is also used for navigation menu items.')) - slug = models.SlugField(_('slug'), max_length=150, - help_text=_('This is used to build the URL for this page')) - parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, - null=True, related_name='children') + slug = models.SlugField( + _('slug'), max_length=150, + help_text=_('This is used to build the URL for this page')) + parent = models.ForeignKey( + 'self', verbose_name=_('Parent'), blank=True, + null=True, related_name='children') # Custom list_filter - see admin/filterspecs.py parent.parent_filter = True in_navigation = models.BooleanField(_('in navigation'), default=False) - override_url = models.CharField(_('override URL'), max_length=255, + override_url = models.CharField( + _('override URL'), max_length=255, blank=True, help_text=_( 'Override the target URL. Be sure to include slashes at the ' 'beginning and at the end if it is a local URL. This ' 'affects both the navigation and subpages\' URLs.')) - redirect_to = models.CharField(_('redirect to'), max_length=255, + redirect_to = models.CharField( + _('redirect to'), max_length=255, blank=True, - help_text=_('Target URL for automatic redirects' + help_text=_( + 'Target URL for automatic redirects' ' or the primary key of a page.')) - _cached_url = models.CharField(_('Cached URL'), max_length=255, blank=True, + _cached_url = models.CharField( + _('Cached URL'), max_length=255, blank=True, editable=False, default='', db_index=True) class Meta: @@ -204,8 +211,10 @@ def is_active(self): if not self.pk: return False - pages = self.__class__.objects.active().filter(tree_id=self.tree_id, - lft__lte=self.lft, rght__gte=self.rght) + pages = self.__class__.objects.active().filter( + tree_id=self.tree_id, + lft__lte=self.lft, + rght__gte=self.rght) return pages.count() > self.level is_active.short_description = _('is active') diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index 14c2432f9..b53f2dbe0 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -16,8 +16,9 @@ class PageSitemap(Sitemap): for submission to index engines. See http://www.sitemaps.org/ for details. """ def __init__(self, navigation_only=False, max_depth=0, changefreq=None, - queryset=None, filter=None, extended_navigation=False, - page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL, *args, **kwargs): + queryset=None, filter=None, extended_navigation=False, + page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL, + *args, **kwargs): """ The PageSitemap accepts the following parameters for customisation of the resulting sitemap.xml output: From 22cc18d78c2b83981636c7f23f35b4f685d9e986 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 17:48:17 +0100 Subject: [PATCH 0884/1590] E128: Only tests left --- .../page/templatetags/feincms_page_tags.py | 39 +++++++++++++------ .../templatetags/applicationcontent_tags.py | 21 +++++----- feincms/templatetags/feincms_tags.py | 5 ++- feincms/templatetags/feincms_thumbnail.py | 3 +- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index f4850158c..08a499ec0 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -12,7 +12,8 @@ from django.http import HttpRequest from feincms import settings as feincms_settings -from feincms.utils.templatetags import (SimpleNodeWithVarAndArgs, +from feincms.utils.templatetags import ( + SimpleNodeWithVarAndArgs, do_simple_node_with_var_and_args_helper, SimpleAssignmentNodeWithVarAndArgs, do_simple_assignment_node_with_var_and_args_helper) @@ -89,8 +90,8 @@ def feincms_nav(context, feincms_page, level=1, depth=1): if parent: if getattr(parent, 'navigation_extension', None): # Special case for navigation extensions - return list(parent.extended_navigation(depth=depth, - request=context.get('request'))) + return list(parent.extended_navigation( + depth=depth, request=context.get('request'))) # Apply descendant filter queryset &= parent.get_descendants() @@ -168,7 +169,9 @@ def what(self, page, args): return page.get_ancestors()[level - 1].get_absolute_url() except IndexError: return '#' -register.tag('feincms_parentlink', + +register.tag( + 'feincms_parentlink', do_simple_node_with_var_and_args_helper(ParentLinkNode)) @@ -226,13 +229,17 @@ def what(self, page, args): # hardcoded paths... bleh if key in translations: - links.append((key, name, + links.append(( + key, + name, translations[key].get_absolute_url() + trailing_path)) elif not only_existing: links.append((key, name, None)) return links -register.tag('feincms_languagelinks', + +register.tag( + 'feincms_languagelinks', do_simple_assignment_node_with_var_and_args_helper(LanguageLinksNode)) @@ -295,7 +302,9 @@ def what(self, page, args, default=None): language = settings.LANGUAGES[0][0] return _translate_page_into(page, language, default=default) -register.tag('feincms_translatedpage', + +register.tag( + 'feincms_translatedpage', do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNode)) @@ -305,7 +314,9 @@ def what(self, page, args): return super(TranslatedPageNodeOrBase, self).what( page, args, default=getattr(page, 'get_original_translation', page)) -register.tag('feincms_translatedpage_or_base', + +register.tag( + 'feincms_translatedpage_or_base', do_simple_assignment_node_with_var_and_args_helper( TranslatedPageNodeOrBase)) @@ -347,7 +358,8 @@ def feincms_breadcrumbs(page, include_self=True): # ------------------------------------------------------------------------ def _is_parent_of(page1, page2): - return (page1.tree_id == page2.tree_id + return ( + page1.tree_id == page2.tree_id and page1.lft < page2.lft and page1.rght > page2.rght) @@ -370,7 +382,8 @@ def is_parent_of(page1, page2): # ------------------------------------------------------------------------ def _is_equal_or_parent_of(page1, page2): - return (page1.tree_id == page2.tree_id + return ( + page1.tree_id == page2.tree_id and page1.lft <= page2.lft and page1.rght >= page2.rght) @@ -445,7 +458,8 @@ def siblings_along_path_to(page_list, page2): # NOTE: This assumes that the input list actually is complete (ie. # comes from feincms_nav). We'll cope with the fall-out of that # assumption when it happens... - ancestors = [a_page for a_page in page_list + ancestors = [ + a_page for a_page in page_list if _is_equal_or_parent_of(a_page, page2)] top_level = min((a_page.level for a_page in page_list)) @@ -470,7 +484,8 @@ def siblings_along_path_to(page_list, page2): return siblings except (AttributeError, ValueError) as e: - logger.warn("siblings_along_path_to caught exception: %s", + logger.warn( + "siblings_along_path_to caught exception: %s", format_exception(e)) return () diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index 57641821d..7da297124 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -4,12 +4,12 @@ from django.template.defaulttags import kwarg_re from django.utils.encoding import smart_str -from feincms.content.application.models import (ApplicationContent, - app_reverse as do_app_reverse) +from feincms.content.application.models import ( + ApplicationContent, app_reverse as do_app_reverse) from feincms.templatetags.feincms_tags import _render_content # backwards compatibility import -from feincms.templatetags.fragment_tags import (fragment, get_fragment, - has_fragment) +from feincms.templatetags.fragment_tags import ( + fragment, get_fragment, has_fragment) register = template.Library() @@ -49,13 +49,15 @@ def __init__(self, view_name, urlconf, args, kwargs, asvar): def render(self, context): args = [arg.resolve(context) for arg in self.args] - kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context)) - for k, v in self.kwargs.items()]) + kwargs = dict([ + (smart_str(k, 'ascii'), v.resolve(context)) + for k, v in self.kwargs.items()]) view_name = self.view_name.resolve(context) urlconf = self.urlconf.resolve(context) try: - url = do_app_reverse(view_name, urlconf, args=args, kwargs=kwargs, + url = do_app_reverse( + view_name, urlconf, args=args, kwargs=kwargs, current_app=context.current_app) except NoReverseMatch: if self.asvar is None: @@ -100,8 +102,9 @@ def app_reverse(parser, token): """ bits = token.split_contents() if len(bits) < 3: - raise TemplateSyntaxError("'%s' takes at least two arguments" - " (path to a view and a urlconf)" % bits[0]) + raise TemplateSyntaxError( + "'%s' takes at least two arguments" + " (path to a view and a urlconf)" % bits[0]) viewname = parser.compile_filter(bits[1]) urlconf = parser.compile_filter(bits[2]) args = [] diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index d75ef6c95..e3a64aef5 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -46,7 +46,8 @@ def feincms_render_region(context, feincms_object, region, request=None): """ {% feincms_render_region feincms_page "main" request %} """ - return u''.join(_render_content(content, request=request, context=context) + return u''.join( + _render_content(content, request=request, context=context) for content in getattr(feincms_object.content, region)) @@ -75,7 +76,7 @@ def feincms_frontend_editing(cms_obj, request): @register.inclusion_tag('admin/feincms/content_type_selection_widget.html', - takes_context=True) + takes_context=True) def show_content_type_selection_widget(context, region): """ {% show_content_type_selection_widget region %} diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index b67a1ae10..361cdeafc 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -179,7 +179,8 @@ def generate(self, storage, original, size, miniature): buf = BytesIO() if image.mode not in ('RGBA', 'RGB', 'L'): image = image.convert('RGBA') - image.save(buf, + image.save( + buf, format if format.lower() in ('jpg', 'jpeg', 'png') else 'jpeg', quality=90) raw_data = buf.getvalue() From 1772d2fb44cd022b2bf7bc733588de083de631e8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 26 Nov 2013 19:57:55 +0100 Subject: [PATCH 0885/1590] flake8 clean --- tests/testapp/applicationcontent_urls.py | 3 +- tests/testapp/blog_urls.py | 23 +++-- tests/testapp/models.py | 51 +++++++---- tests/testapp/navigation_extensions.py | 4 +- tests/testapp/tests/test_cms.py | 31 ++++--- tests/testapp/tests/test_page.py | 105 ++++++++++++++--------- tests/testapp/tests/test_stuff.py | 8 +- tests/testapp/urls.py | 19 ++-- 8 files changed, 156 insertions(+), 88 deletions(-) diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index bde01dc90..7df7d9148 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -41,7 +41,8 @@ def inheritance20(request): return 'inheritance20.html', {'from_appcontent': 42} -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'^$', module_root, name='ac_module_root'), url(r'^args_test/([^/]+)/([^/]+)/$', args_test, name='ac_args_test'), url(r'^kwargs_test/(?P<kwarg2>[^/]+)/(?P<kwarg1>[^/]+)/$', args_test), diff --git a/tests/testapp/blog_urls.py b/tests/testapp/blog_urls.py index 70932bbd2..90d7ca2ce 100644 --- a/tests/testapp/blog_urls.py +++ b/tests/testapp/blog_urls.py @@ -4,11 +4,20 @@ from feincms.module.blog.models import Entry -urlpatterns = patterns('', - url(r'^(?P<pk>\d+)/', generic.DetailView.as_view( - queryset=Entry.objects.all(), - ), name='blog_entry_detail'), - url(r'^$', generic.ListView.as_view( - queryset=Entry.objects.all(), - ), name='blog_entry_list'), +urlpatterns = patterns( + '', + url( + r'^(?P<pk>\d+)/', + generic.DetailView.as_view( + queryset=Entry.objects.all(), + ), + name='blog_entry_detail' + ), + url( + r'^$', + generic.ListView.as_view( + queryset=Entry.objects.all(), + ), + name='blog_entry_list' + ), ) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 22c26056a..9b3c45ab7 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -10,8 +10,8 @@ from feincms.content.image.models import ImageContent from feincms.content.medialibrary.models import MediaFileContent from feincms.content.application.models import ApplicationContent -from feincms.module.page.extensions.navigation import (NavigationExtension, - PagePretender) +from feincms.module.page.extensions.navigation import ( + NavigationExtension, PagePretender) from feincms.content.application.models import reverse from mptt.models import MPTTModel @@ -27,12 +27,18 @@ ), }) Page.create_content_type(RawContent) -Page.create_content_type(MediaFileContent, TYPE_CHOICES=( - ('default', 'Default position'), -)) -Page.create_content_type(ImageContent, POSITION_CHOICES=( - ('default', 'Default position'), -)) +Page.create_content_type( + MediaFileContent, + TYPE_CHOICES=( + ('default', 'Default position'), + ) +) +Page.create_content_type( + ImageContent, + POSITION_CHOICES=( + ('default', 'Default position'), + ) +) def get_admin_fields(form, *args, **kwargs): @@ -48,10 +54,13 @@ def get_admin_fields(form, *args, **kwargs): } -Page.create_content_type(ApplicationContent, APPLICATIONS=( - ('testapp.blog_urls', 'Blog', {'admin_fields': get_admin_fields}), - ('whatever', 'Test Urls', {'urls': 'testapp.applicationcontent_urls'}), -)) +Page.create_content_type( + ApplicationContent, + APPLICATIONS=( + ('testapp.blog_urls', 'Blog', {'admin_fields': get_admin_fields}), + ('whatever', 'Test Urls', {'urls': 'testapp.applicationcontent_urls'}), + ) +) Entry.register_extensions( 'feincms.module.extensions.seo', @@ -63,9 +72,11 @@ def get_admin_fields(form, *args, **kwargs): ('main', 'Main region'), ) Entry.create_content_type(RawContent) -Entry.create_content_type(ImageContent, POSITION_CHOICES=( - ('default', 'Default position'), -)) +Entry.create_content_type( + ImageContent, POSITION_CHOICES=( + ('default', 'Default position'), + ) +) class BlogEntriesNavigationExtension(NavigationExtension): @@ -82,7 +93,8 @@ def children(self, page, **kwargs): title=entry.title, url=reverse( 'testapp.blog_urls/blog_entry_detail', - kwargs={'object_id': entry.id}), + kwargs={'object_id': entry.id} + ), ) Page.register_extensions( @@ -105,8 +117,8 @@ def children(self, page, **kwargs): class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() - parent = models.ForeignKey('self', blank=True, null=True, - related_name='children') + parent = models.ForeignKey( + 'self', blank=True, null=True, related_name='children') class Meta: ordering = ['tree_id', 'lft'] @@ -118,6 +130,7 @@ def __str__(self): # add m2m field to entry so it shows up in entry admin -Entry.add_to_class('categories', +Entry.add_to_class( + 'categories', models.ManyToManyField(Category, blank=True, null=True)) EntryAdmin.list_filter += ('categories',) diff --git a/tests/testapp/navigation_extensions.py b/tests/testapp/navigation_extensions.py index 7a34cc893..749aa0762 100644 --- a/tests/testapp/navigation_extensions.py +++ b/tests/testapp/navigation_extensions.py @@ -1,5 +1,5 @@ -from feincms.module.page.extensions.navigation import (NavigationExtension, - PagePretender) +from feincms.module.page.extensions.navigation import ( + NavigationExtension, PagePretender) class PassthroughExtension(NavigationExtension): diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 6a6e5f5f9..e41ad5741 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -39,17 +39,20 @@ def test_01_simple_content_type_creation(self): # test creating a cotent with arguments, but no initialize_type # classmethod - ExampleCMSBase.create_content_type(VideoContent, + ExampleCMSBase.create_content_type( + VideoContent, arbitrary_arg='arbitrary_value') # content_type_for should return None if it does not have a subclass # registered self.assertEqual(ExampleCMSBase.content_type_for(Empty), None) - self.assertTrue('filecontent' not in dict( - ExampleCMSBase.template.regions[0].content_types).keys()) - self.assertTrue('filecontent' in dict( - ExampleCMSBase.template.regions[1].content_types).keys()) + self.assertTrue( + 'filecontent' not in dict( + ExampleCMSBase.template.regions[0].content_types).keys()) + self.assertTrue( + 'filecontent' in dict( + ExampleCMSBase.template.regions[1].content_types).keys()) def test_02_rsscontent_creation(self): # this test resides in its own method because the required feedparser @@ -88,7 +91,8 @@ def test_04_mediafilecontent_creation(self): from feincms.content.medialibrary.models import MediaFileContent # no TYPE_CHOICES, should raise - self.assertRaises(ImproperlyConfigured, + self.assertRaises( + ImproperlyConfigured, lambda: ExampleCMSBase.create_content_type(MediaFileContent)) def test_05_non_abstract_content_type(self): @@ -97,7 +101,8 @@ def test_05_non_abstract_content_type(self): class TestContentType(models.Model): pass - self.assertRaises(ImproperlyConfigured, + self.assertRaises( + ImproperlyConfigured, lambda: ExampleCMSBase.create_content_type(TestContentType)) def test_06_videocontent(self): @@ -133,10 +138,12 @@ def test_08_creating_two_content_types_in_same_application(self): ct = ExampleCMSBase.content_type_for(RawContent) self.assertEqual(ct._meta.db_table, 'tests_examplecmsbase_rawcontent') - ExampleCMSBase2.create_content_type(RawContent, + ExampleCMSBase2.create_content_type( + RawContent, class_name='RawContent2') ct2 = ExampleCMSBase2.content_type_for(RawContent) - self.assertEqual(ct2._meta.db_table, + self.assertEqual( + ct2._meta.db_table, 'tests_examplecmsbase2_rawcontent2') def test_09_related_objects_cache(self): @@ -149,7 +156,8 @@ def test_09_related_objects_cache(self): related models have been defined. """ class Attachment(models.Model): - base = models.ForeignKey(ExampleCMSBase, + base = models.ForeignKey( + ExampleCMSBase, related_name='test_related_name') # See issue #323 on Github. @@ -163,7 +171,8 @@ class Attachment(models.Model): #self.assertFalse(hasattr(Attachment, 'anycontents')) class AnyContent(models.Model): - attachment = models.ForeignKey(Attachment, + attachment = models.ForeignKey( + Attachment, related_name='anycontents') class Meta: diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index dfcf00dec..0af78ac4a 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -25,8 +25,8 @@ from mptt.exceptions import InvalidMove from feincms import settings as feincms_settings -from feincms.content.application.models import (app_reverse, - cycle_app_reverse_cache) +from feincms.content.application.models import ( + app_reverse, cycle_app_reverse_cache) from feincms.content.image.models import ImageContent from feincms.content.raw.models import RawContent from feincms.content.richtext.models import RichTextContent @@ -45,7 +45,10 @@ # ------------------------------------------------------------------------ class PagesTestCase(TestCase): def setUp(self): - u = User(username='test', is_active=True, is_staff=True, + u = User( + username='test', + is_active=True, + is_staff=True, is_superuser=True) u.set_password('test') u.save() @@ -74,7 +77,7 @@ def login(self): self.assertTrue(self.client.login(username='test', password='test')) def create_page_through_admin(self, title='Test page', parent='', - **kwargs): + **kwargs): dic = { 'title': title, 'slug': kwargs.get('slug', slugify(title)), @@ -443,8 +446,8 @@ def test_10_mediafile_and_imagecontent(self): self.assertEqual(force_text(mediafile), 'somefile.jpg') - mediafile.translations.create(caption='something', - language_code='%s-ha' % short_language_code()) + mediafile.translations.create( + caption='something', language_code='%s-ha' % short_language_code()) mediafile.purge_translation_cache() self.assertTrue('something' in force_text(mediafile)) @@ -592,7 +595,8 @@ def test_13_inheritance_and_ct_tracker(self): self.assertNumQueries( 0, lambda: page2.content.sidebar[0].render()) - self.assertEqual(u''.join(c.render() for c in page2.content.main), + self.assertEqual( + u''.join(c.render() for c in page2.content.main), 'Something elseWhatever') self.assertEqual(page2.content.sidebar[0].render(), 'Something') @@ -663,8 +667,8 @@ def test_15_frontend_editing(self): request = Empty() request.COOKIES = {'frontend_editing': "True"} - self.assertIn('class="fe_box"', - page.content.main[0].fe_render(request=request)) + self.assertIn( + 'class="fe_box"', page.content.main[0].fe_render(request=request)) def test_15_b_client_frontend_editing(self): self.create_default_page_set() @@ -688,17 +692,17 @@ def test_15_b_client_frontend_editing(self): Page.register_request_processor( processors.frontendediting_request_processor, key='frontend_editing') - response = self.client.get(page.get_absolute_url() + - '?frontend_editing=1', + response = self.client.get( + page.get_absolute_url() + '?frontend_editing=1', follow=True) self.assertRedirects(response, page.get_absolute_url()) self.assertIn('class="fe_box"', response.content.decode('utf-8')) self.assertIn('frontend_editing', self.client.cookies) # turn off edit on site - response = self.client.get(page.get_absolute_url() + - '?frontend_editing=0', - follow=True) + response = self.client.get( + page.get_absolute_url() + '?frontend_editing=0', + follow=True) self.assertRedirects(response, page.get_absolute_url()) self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) @@ -825,9 +829,11 @@ def test_17_page_template_tags(self): '{% feincms_breadcrumbs feincms_page %}') rendered = t.render(context) self.assertTrue("Test child page" in rendered) - self.assertTrue('href="/test-page/">Test page</a>' in rendered, + self.assertTrue( + 'href="/test-page/">Test page</a>' in rendered, msg="The parent page should be a breadcrumb link") - self.assertTrue('href="/test-page/test-child-page/"' not in rendered, + self.assertTrue( + 'href="/test-page/test-child-page/"' not in rendered, msg="The current page should not be a link in the breadcrumbs") t = template.Template( @@ -1090,20 +1096,26 @@ def test_19_page_manager(self): page.active = True page.save() - self.assertRaises(Page.DoesNotExist, + self.assertRaises( + Page.DoesNotExist, lambda: Page.objects.page_for_path(page.get_absolute_url())) - self.assertRaises(Page.DoesNotExist, + self.assertRaises( + Page.DoesNotExist, lambda: Page.objects.best_match_for_path( page.get_absolute_url() + 'something/hello/')) - self.assertRaises(Http404, + self.assertRaises( + Http404, lambda: Page.objects.best_match_for_path( '/blabla/blabla/', raise404=True)) - self.assertRaises(Http404, + self.assertRaises( + Http404, lambda: Page.objects.page_for_path('/asdf/', raise404=True)) - self.assertRaises(Page.DoesNotExist, + self.assertRaises( + Page.DoesNotExist, lambda: Page.objects.best_match_for_path('/blabla/blabla/')) - self.assertRaises(Page.DoesNotExist, + self.assertRaises( + Page.DoesNotExist, lambda: Page.objects.page_for_path('/asdf/')) request = Empty() @@ -1121,22 +1133,25 @@ def test_19_page_manager(self): page.active = False page.save() - self.assertRaises(Http404, + self.assertRaises( + Http404, lambda: Page.objects.for_request(request, raise404=True)) page.active = True page.save() - self.assertRaises(Http404, + self.assertRaises( + Http404, lambda: Page.objects.for_request(request, raise404=True)) page.parent.active = True page.parent.save() self.assertEqual(page, Page.objects.for_request(request)) - self.assertEqual(page, - Page.objects.page_for_path(page.get_absolute_url())) - self.assertEqual(page, + self.assertEqual( + page, Page.objects.page_for_path(page.get_absolute_url())) + self.assertEqual( + page, Page.objects.best_match_for_path( page.get_absolute_url() + 'something/hello/')) @@ -1177,7 +1192,8 @@ def test_20_redirects(self): # page2 has been modified too, but its URL should not have changed try: self.assertRedirects( - self.client.get('/blablabla/'), page1.get_absolute_url()) + self.client.get('/blablabla/'), + page1.get_absolute_url()) except TemplateDoesNotExist as e: # catch the error from rendering page1 if e.args != ('feincms_base.html',): @@ -1301,7 +1317,8 @@ def test_25_applicationcontent(self): response = self.client.get( page.get_absolute_url() + 'full_reverse_test/') self.assertContains(response, 'home:/test-page/test-child-page/') - self.assertContains(response, + self.assertContains( + response, 'args:/test-page/test-child-page/args_test/xy/zzy/') self.assertContains(response, 'base:/test/') self.assertContains(response, 'homeas:/test-page/test-child-page/') @@ -1311,16 +1328,19 @@ def test_25_applicationcontent(self): '/test-page/test-child-page/') if hasattr(self, 'assertNumQueries'): - self.assertNumQueries(0, + self.assertNumQueries( + 0, lambda: app_reverse( 'ac_module_root', 'testapp.applicationcontent_urls')) cycle_app_reverse_cache() - self.assertNumQueries(1, + self.assertNumQueries( + 1, lambda: app_reverse( 'ac_module_root', 'testapp.applicationcontent_urls')) - self.assertNumQueries(0, + self.assertNumQueries( + 0, lambda: app_reverse( 'ac_module_root', 'testapp.applicationcontent_urls')) @@ -1349,7 +1369,8 @@ def test_25_applicationcontent(self): # Test standalone behavior self.assertEqual( - self.client.get(page.get_absolute_url() + 'response/', + self.client.get( + page.get_absolute_url() + 'response/', HTTP_X_REQUESTED_WITH='XMLHttpRequest').content, self.client.get( page.get_absolute_url() + 'response_decorated/').content) @@ -1392,7 +1413,8 @@ def test_25_applicationcontent(self): # Ensure ApplicationContent's admin_fields support works properly self.login() - self.assertContains(self.client.get('/admin/page/page/%d/' % page.id), + self.assertContains( + self.client.get('/admin/page/page/%d/' % page.id), 'exclusive_subpages') def test_26_page_form_initial(self): @@ -1505,12 +1527,14 @@ def test_29_medialibrary_admin(self): }) self.assertRedirects(response, '/admin/medialibrary/mediafile/') - self.assertEqual(MediaFile.objects.count(), 11, + self.assertEqual( + MediaFile.objects.count(), + 11, "Upload of media files with ZIP does not work") dn = os.path.dirname - path = os.path.join(dn(dn(dn(dn(__file__)))), - 'docs', 'images', 'tree_editor.png') + path = os.path.join( + dn(dn(dn(dn(__file__)))), 'docs', 'images', 'tree_editor.png') response = self.client.post('/admin/medialibrary/mediafile/add/', { 'file': open(path, 'rb'), @@ -1520,7 +1544,8 @@ def test_29_medialibrary_admin(self): }) self.assertRedirects(response, '/admin/medialibrary/mediafile/') - self.assertContains(self.client.get('/admin/medialibrary/mediafile/'), + self.assertContains( + self.client.get('/admin/medialibrary/mediafile/'), '100x100.png" alt="" />') stats = list(MediaFile.objects.values_list('type', flat=True)) @@ -1546,8 +1571,8 @@ def test_31_sites_framework_associating_with_single_site(self): site_2 = Site.objects.create(name='site 2', domain='2.example.com') self.create_page_through_admin( 'site 1 homepage', override_url='/', active=True) - self.create_page_through_admin('site 2 homepage', override_url='/', - site=site_2.id, active=True) + self.create_page_through_admin( + 'site 2 homepage', override_url='/', site=site_2.id, active=True) self.assertEqual(Page.objects.count(), 2) self.assertEqual(Page.objects.active().count(), 1) diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 441171394..9c374cc8a 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -66,7 +66,8 @@ def test_get_object(self): self.assertEqual(get_object, get_object('feincms.utils.get_object')) def test_collect_dict_values(self): - self.assertEqual({'a': [1, 2], 'b': [3]}, + self.assertEqual( + {'a': [1, 2], 'b': [3]}, collect_dict_values([('a', 1), ('a', 2), ('b', 3)])) def test_shorten_string(self): @@ -114,7 +115,10 @@ class ExampleCMSBase2(Base): class BlogTestCase(TestCase): def setUp(self): - u = User(username='test', is_active=True, is_staff=True, + u = User( + username='test', + is_active=True, + is_staff=True, is_superuser=True) u.set_password('test') u.save() diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index b8d9511b1..fb87587cd 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -11,14 +11,21 @@ admin.autodiscover() -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'^admin/', include(admin.site.urls)), - url(r'^media/(?P<path>.*)$', 'django.views.static.serve', - {'document_root': os.path.join(os.path.dirname(__file__), 'media/')}), - - url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', - {'sitemaps': sitemaps}), + url( + r'^media/(?P<path>.*)$', + 'django.views.static.serve', + {'document_root': os.path.join(os.path.dirname(__file__), 'media/')}, + ), + + url( + r'^sitemap\.xml$', + 'django.contrib.sitemaps.views.sitemap', + {'sitemaps': sitemaps}, + ), url(r'', include('feincms.contrib.preview.urls')), url(r'', include('feincms.views.cbv.urls')), From f77d237c821c0429f96ebe73def1a29752ade6a1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 27 Nov 2013 08:45:58 +0100 Subject: [PATCH 0886/1590] Go through the list of changes, update the relnotes, add a JS comment --- docs/releases/1.9.rst | 6 ++---- feincms/static/feincms/item_editor.js | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index 19909ac04..bd48e1c79 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -5,10 +5,6 @@ FeinCMS 1.9 release notes (upcoming) Welcome to FeinCMS 1.9! -Major feature 1 -=============== - - Extensions in the item editor ============================= @@ -57,6 +53,8 @@ Notable features and improvements cleanups. `flake8 <https://pypi.python.org/pypi/flake8>`_ runs should not show any warnings. +* Extension classes can be passed directly to ``register_extensions()`` now. + Bugfixes ======== diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 5cb8a23c1..33c89c7b0 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -195,6 +195,8 @@ var old_region_id = REGION_MAP.indexOf(item.find("."+field).val()); item.find("."+field).val(REGION_MAP[value]); + // show/hide the empty machine message in the source and + // target region. old_region_item = $("#"+REGION_MAP[old_region_id]+"_body"); if (old_region_item.children("div.order-machine").children().length == 0) old_region_item.children("div.empty-machine-msg").show(); From ab563d31fbd57e848cb7f486d0ba863aa46b0823 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 27 Nov 2013 09:04:31 +0100 Subject: [PATCH 0887/1590] Order release notes chronologically --- docs/index.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 434683fb0..f0bea9d4e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -92,14 +92,14 @@ Releases .. toctree:: :maxdepth: 1 - releases/1.9 - releases/1.8 - releases/1.7 - releases/1.6 - releases/1.5 - releases/1.4 - releases/1.3 releases/1.2 + releases/1.3 + releases/1.4 + releases/1.5 + releases/1.6 + releases/1.7 + releases/1.8 + releases/1.9 Indices and tables From 2c89baf4f502fc4281e05aca8d3254fe4991fab5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 27 Nov 2013 09:19:02 +0100 Subject: [PATCH 0888/1590] Remove autodoc extension -- it never worked correctly everywhere ever --- docs/api/admin.rst | 29 -------- docs/api/blog.rst | 26 ------- docs/api/commands.rst | 37 --------- docs/api/contenttypes.rst | 87 ---------------------- docs/api/contextprocessors.rst | 6 -- docs/api/contrib.rst | 23 ------ docs/api/core.rst | 18 ----- docs/api/medialibrary.rst | 33 --------- docs/api/page.rst | 132 --------------------------------- docs/api/settings.rst | 6 -- docs/api/shortcuts.rst | 6 -- docs/api/templatetags.rst | 37 --------- docs/api/translations.rst | 6 -- docs/api/utils.rst | 26 ------- docs/api/views.rst | 14 ---- docs/conf.py | 2 +- docs/contenttypes.rst | 6 +- docs/index.rst | 24 ------ 18 files changed, 4 insertions(+), 514 deletions(-) delete mode 100644 docs/api/admin.rst delete mode 100644 docs/api/blog.rst delete mode 100644 docs/api/commands.rst delete mode 100644 docs/api/contenttypes.rst delete mode 100644 docs/api/contextprocessors.rst delete mode 100644 docs/api/contrib.rst delete mode 100644 docs/api/core.rst delete mode 100644 docs/api/medialibrary.rst delete mode 100644 docs/api/page.rst delete mode 100644 docs/api/settings.rst delete mode 100644 docs/api/shortcuts.rst delete mode 100644 docs/api/templatetags.rst delete mode 100644 docs/api/translations.rst delete mode 100644 docs/api/utils.rst delete mode 100644 docs/api/views.rst diff --git a/docs/api/admin.rst b/docs/api/admin.rst deleted file mode 100644 index 980df0e2c..000000000 --- a/docs/api/admin.rst +++ /dev/null @@ -1,29 +0,0 @@ -Admin classes -============= - -ItemEditor ----------- - -.. automodule:: feincms.admin.item_editor - :members: - :noindex: - -.. automodule:: feincms.templatetags.feincms_admin_tags - :members: - :noindex: - - -TreeEditor ----------- - -.. automodule:: feincms.admin.tree_editor - :members: - :noindex: - - -FilterSpec classes for ``list_filter`` customization ----------------------------------------------------- - -.. automodule:: feincms.admin.filterspecs - :members: - :noindex: diff --git a/docs/api/blog.rst b/docs/api/blog.rst deleted file mode 100644 index cd6f97cd3..000000000 --- a/docs/api/blog.rst +++ /dev/null @@ -1,26 +0,0 @@ -Blog module -=========== - - -.. automodule:: feincms.module.blog.models - :members: - :noindex: - - -Extensions ----------- - -Tagging -******* - -.. automodule:: feincms.module.blog.extensions.tags - :members: - :noindex: - - -Blog entry translations -*********************** - -.. automodule:: feincms.module.blog.extensions.translations - :members: - :noindex: diff --git a/docs/api/commands.rst b/docs/api/commands.rst deleted file mode 100644 index 62627d17c..000000000 --- a/docs/api/commands.rst +++ /dev/null @@ -1,37 +0,0 @@ -Management commands -=================== - -Database schema checker ------------------------ - -.. automodule:: feincms.management.checker - :members: - :noindex: - - -Content-type specific management commands ------------------------------------------ - -.. automodule:: feincms.management.commands.update_rsscontent - :members: - :noindex: - - -Page tree rebuilders --------------------- - -Those should not normally be used. Older versions of MPTT sometimes -got confused with repeated saves and tree-structure changes. These -management commands helped cleaning up the mess. - -.. automodule:: feincms.management.commands.rebuild_mptt - :members: - :noindex: - - -Miscellaneous commands ----------------------- - -.. automodule:: feincms.management.commands.feincms_validate - :members: - :noindex: diff --git a/docs/api/contenttypes.rst b/docs/api/contenttypes.rst deleted file mode 100644 index c5d81704b..000000000 --- a/docs/api/contenttypes.rst +++ /dev/null @@ -1,87 +0,0 @@ -Content types -============= - -ApplicationContent ------------------- - -.. automodule:: feincms.content.application.models - :members: - :noindex: - -CommentsContent ---------------- - -.. automodule:: feincms.content.comments.models - :members: - :noindex: - -ContactFormContent ------------------- - -.. automodule:: feincms.content.contactform.models - :members: - :noindex: - -FileContent ------------ - -.. automodule:: feincms.content.file.models - :members: - :noindex: - -ImageContent ------------- - -.. automodule:: feincms.content.image.models - :members: - :noindex: - -MediaFileContent ----------------- - -.. automodule:: feincms.content.medialibrary.models - :members: - :noindex: - -RawContent ----------- - -.. automodule:: feincms.content.raw.models - :members: - :noindex: - -RichTextContent ---------------- - -.. automodule:: feincms.content.richtext.models - :members: - :noindex: - -RSSContent ----------- - -.. automodule:: feincms.content.rss.models - :members: - :noindex: - -SectionContent --------------- - -.. automodule:: feincms.content.section.models - :members: - :noindex: - -TemplateContent ---------------- - -.. automodule:: feincms.content.template.models - :members: - :noindex: - -VideoContent ------------- - -.. automodule:: feincms.content.video.models - :members: - :noindex: - diff --git a/docs/api/contextprocessors.rst b/docs/api/contextprocessors.rst deleted file mode 100644 index ec08b0211..000000000 --- a/docs/api/contextprocessors.rst +++ /dev/null @@ -1,6 +0,0 @@ -Context processors -================== - -.. automodule:: feincms.context_processors - :members: - :noindex: diff --git a/docs/api/contrib.rst b/docs/api/contrib.rst deleted file mode 100644 index 398f00e91..000000000 --- a/docs/api/contrib.rst +++ /dev/null @@ -1,23 +0,0 @@ -Contrib -======= - - -Model and form fields ---------------------- - -.. automodule:: feincms.contrib.fields - :members: - :noindex: - - -.. automodule:: feincms.contrib.richtext - :members: - :noindex: - - -Tagging -------- - -.. automodule:: feincms.contrib.tagging - :members: - :noindex: diff --git a/docs/api/core.rst b/docs/api/core.rst deleted file mode 100644 index cbc5e4e53..000000000 --- a/docs/api/core.rst +++ /dev/null @@ -1,18 +0,0 @@ -FeinCMS core -============ - - -General functions ------------------ - -.. automodule:: feincms - :members: - :noindex: - - -Base models ------------ - -.. automodule:: feincms.models - :members: - :noindex: diff --git a/docs/api/medialibrary.rst b/docs/api/medialibrary.rst deleted file mode 100644 index ebf0f213c..000000000 --- a/docs/api/medialibrary.rst +++ /dev/null @@ -1,33 +0,0 @@ -Media library -============= - -Models ------- - -.. automodule:: feincms.module.medialibrary.models - :members: - :noindex: - - -Admin classes -------------- - -.. automodule:: feincms.module.medialibrary.modeladmins - :members: - :noindex: - -.. automodule:: feincms.module.medialibrary.forms - :members: - :noindex: - -.. automodule:: feincms.module.medialibrary.zip - :members: - :noindex: - - -Fields ------- - -.. automodule:: feincms.module.medialibrary.fields - :members: - :noindex: diff --git a/docs/api/page.rst b/docs/api/page.rst deleted file mode 100644 index f524d8cfb..000000000 --- a/docs/api/page.rst +++ /dev/null @@ -1,132 +0,0 @@ -Page module -=========== - - -Models ------- - -.. automodule:: feincms.module.page.models - :members: - :noindex: - - -Request and response processors -------------------------------- - -.. automodule:: feincms.module.page.processors - :members: - :noindex: - - -Admin classes -------------- - -.. automodule:: feincms.module.page.modeladmins - :members: - :noindex: - -.. automodule:: feincms.module.page.forms - :members: - :noindex: - - -Sitemap module --------------- - -.. automodule:: feincms.module.page.sitemap - :members: - :noindex: - - -Extensions ----------- - -Page excerpts -************* - -.. automodule:: feincms.module.page.extensions.excerpt - :members: - :noindex: - - -Navigation extensions -********************* - -.. automodule:: feincms.module.page.extensions.navigation - :members: - :noindex: - - -Related pages -************* - -.. automodule:: feincms.module.page.extensions.relatedpages - :members: - :noindex: - - -Symlinked page content -********************** - -.. automodule:: feincms.module.page.extensions.symlinks - :members: - :noindex: - - -Flexible page titles -******************** - -.. automodule:: feincms.module.page.extensions.titles - :members: - :noindex: - - -Extensions not specific to the page module ------------------------------------------- - -Creation and modification timestamps -************************************ - -.. automodule:: feincms.module.extensions.changedate - :members: - :noindex: - - -Content type count denormalization -********************************** - -.. automodule:: feincms.module.extensions.ct_tracker - :members: - :noindex: - - -Date-based publishing -********************* - -.. automodule:: feincms.module.extensions.datepublisher - :members: - :noindex: - - -Featured items -************** - -.. automodule:: feincms.module.extensions.featured - :members: - :noindex: - - -Search engine optimization fields -********************************* - -.. automodule:: feincms.module.extensions.seo - :members: - :noindex: - - -Translations -************ - -.. automodule:: feincms.module.extensions.translations - :members: - :noindex: diff --git a/docs/api/settings.rst b/docs/api/settings.rst deleted file mode 100644 index 417142193..000000000 --- a/docs/api/settings.rst +++ /dev/null @@ -1,6 +0,0 @@ -Settings -======== - -.. automodule:: feincms.default_settings - :members: - :noindex: diff --git a/docs/api/shortcuts.rst b/docs/api/shortcuts.rst deleted file mode 100644 index d323c02f6..000000000 --- a/docs/api/shortcuts.rst +++ /dev/null @@ -1,6 +0,0 @@ -Shortcuts -========= - -.. automodule:: feincms.shortcuts - :members: - :noindex: diff --git a/docs/api/templatetags.rst b/docs/api/templatetags.rst deleted file mode 100644 index 8bc98c5e9..000000000 --- a/docs/api/templatetags.rst +++ /dev/null @@ -1,37 +0,0 @@ -Template tags -============= - -FeinCMS tags ------------- - -.. automodule:: feincms.templatetags.feincms_tags - :members: - :noindex: - - -Thumbnail filters ------------------ - -.. automodule:: feincms.templatetags.feincms_thumbnail - :members: - :noindex: - - -Page-module specific tags -------------------------- - -.. automodule:: feincms.module.page.templatetags.feincms_page_tags - :members: - :noindex: - - -``ApplicationContent`` tags ---------------------------- - -.. automodule:: feincms.templatetags.applicationcontent_tags - :members: - :noindex: - -.. automodule:: feincms.templatetags.fragment_tags - :members: - :noindex: diff --git a/docs/api/translations.rst b/docs/api/translations.rst deleted file mode 100644 index c55a1f019..000000000 --- a/docs/api/translations.rst +++ /dev/null @@ -1,6 +0,0 @@ -Translations -============ - -.. automodule:: feincms.translations - :members: - :noindex: diff --git a/docs/api/utils.rst b/docs/api/utils.rst deleted file mode 100644 index 4f3b36974..000000000 --- a/docs/api/utils.rst +++ /dev/null @@ -1,26 +0,0 @@ -Utilities -========= - -.. automodule:: feincms.utils - :members: - :noindex: - - -HTML utilities --------------- - -.. automodule:: feincms.utils.html.cleanse - :members: - :noindex: - -.. automodule:: feincms.utils.html.tidy - :members: - :noindex: - - -Template tag helpers --------------------- - -.. automodule:: feincms.utils.templatetags - :members: - :noindex: diff --git a/docs/api/views.rst b/docs/api/views.rst deleted file mode 100644 index c18773bf7..000000000 --- a/docs/api/views.rst +++ /dev/null @@ -1,14 +0,0 @@ -Views and decorators -==================== - -.. automodule:: feincms.views.cbv.views - :members: - :noindex: - - -Decorators ----------- - -.. automodule:: feincms.views.decorators - :members: - :noindex: diff --git a/docs/conf.py b/docs/conf.py index bdb164441..26aa1b611 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,7 +25,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc'] +extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 329ded7f7..89c27bd04 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -461,9 +461,9 @@ This content type scans all template directories for templates below ``content/template/`` and allows the user to select one of these templates which are then rendered using the Django template language. -Note that some file extensions are automatically filtered so they won't -appear in the list, namely anything that matches *.~ and *.tmp will be -ignored. +Note that some file extensions are automatically filtered so they will not +appear in the list, namely any filenames ending with ``.~`` or ``.tmp`` will +be ignored. Also note that a template content is not sandboxed or specially rendered. Whatever a django template can do a TemplateContent snippet can do too, diff --git a/docs/index.rst b/docs/index.rst index f0bea9d4e..7b92fbaae 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -62,30 +62,6 @@ Contents deprecation -API Documentation -================= - -.. toctree:: - :maxdepth: 3 - - - api/core - api/admin - api/page - api/medialibrary - api/blog - api/contenttypes - api/contextprocessors - api/contrib - api/settings - api/shortcuts - api/templatetags - api/translations - api/utils - api/views - api/commands - - Releases ======== From 717c3102628aa2b6149661aa6aca352406a4e09d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 11:58:32 +0100 Subject: [PATCH 0889/1590] Add a new page_is_active tag which also understands page pretenders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Simon Bächler for the report and Bojan Mihelac for a working tag in feincmsext. Fixes #493. --- .../page/templatetags/feincms_page_tags.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 08a499ec0..503f53d58 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -12,6 +12,7 @@ from django.http import HttpRequest from feincms import settings as feincms_settings +from feincms.module.page.extensions.navigation import PagePretender from feincms.utils.templatetags import ( SimpleNodeWithVarAndArgs, do_simple_node_with_var_and_args_helper, @@ -491,3 +492,28 @@ def siblings_along_path_to(page_list, page2): return () # ------------------------------------------------------------------------ + +@register.assignment_tag(takes_context=True) +def page_is_active(context, page, feincms_page=None, path=None): + """ + Usage example:: + + {% feincms_nav feincms_page level=1 as toplevel %} + <ul> + {% for page in toplevel %} + {% page_is_active page as is_active %} + <li {% if is_active %}class="active"{% endif %}> + <a href="{{ page.get_navigation_url }}">{{ page.title }}</a> + <li> + {% endfor %} + </ul> + """ + if isinstance(page, PagePretender): + if path is None: + path = context['request'].path_info + return page.get_absolute_url().startswith(path) + + else: + if feincms_page is None: + feincms_page = context['feincms_page'] + return _is_equal_or_parent_of(page, feincms_page) From fb959fa163ac40880f3154dfe20579c9a0dbf18e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 12:15:46 +0100 Subject: [PATCH 0890/1590] Use the central download cache of pip --- tests/tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/tox.ini b/tests/tox.ini index 6a14ca64f..3a4d952b0 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -14,7 +14,6 @@ envlist = py33-1.7.X, [testenv] -downloadcache = {toxworkdir}/_download/ commands = {envpython} manage.py test {posargs:testapp} --settings=testapp.settings setenv = From d3aa3ae9151023a499b82452b3bcaf349efb65e2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 12:21:05 +0100 Subject: [PATCH 0891/1590] Newer Pillow version in tox.ini, maybe that helps --- tests/tox.ini | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/tox.ini b/tests/tox.ini index 3a4d952b0..8660e80b6 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -25,7 +25,7 @@ basepython = python2.6 deps = django==1.4.7 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -35,7 +35,7 @@ basepython = python2.7 deps = django==1.4.7 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -45,7 +45,7 @@ basepython = python2.6 deps = django==1.5.3 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -55,7 +55,7 @@ basepython = python2.7 deps = django==1.5.3 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -65,7 +65,7 @@ basepython = python2.6 deps = Django==1.6.0 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -75,7 +75,7 @@ basepython = python2.7 deps = Django==1.6.0 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -85,7 +85,7 @@ basepython = python2.7 deps = --editable=git+git://github.com/django/django.git@master#egg=django-dev django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -95,7 +95,7 @@ basepython = python3.3 deps = Django==1.5.4 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 @@ -105,7 +105,7 @@ basepython = python3.3 deps = Django==1.6.0 django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 @@ -115,7 +115,7 @@ basepython = python3.3 deps = --editable=git+git://github.com/django/django.git@master#egg=django-dev django-mptt==0.6.0 - Pillow==2.1.0 + Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 From 73a3da02ac2429ded9d6b3d5114e025bb1111ff7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 12:37:51 +0100 Subject: [PATCH 0892/1590] Add some documentation for page_is_active --- docs/releases/1.9.rst | 20 ++++++++++++++++++++ docs/templatetags.rst | 25 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index bd48e1c79..0134d8097 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -12,6 +12,26 @@ Extension fieldsets are now presented using a tabbed interface in the item editor as well to raise their visibility. +A better way to mark pages as active in the navigation +====================================================== + +The new template tag ``{% page_is_active %}`` knows how to handle regular +pages and also page pretenders from navigation extensions. + +The following template snippet shows the recommended method of marking +pages as active:: + + {% feincms_nav feincms_page level=1 as toplevel %} + <ul> + {% for page in toplevel %} + {% page_is_active page as is_active %} + <li {% if is_active %}class="active"{% endif %}> + <a href="{{ page.get_navigation_url }}">{{ page.title }}</a> + <li> + {% endfor %} + </ul> + + Backwards-incompatible changes ============================== diff --git a/docs/templatetags.rst b/docs/templatetags.rst index c659f0892..203168b87 100644 --- a/docs/templatetags.rst +++ b/docs/templatetags.rst @@ -199,6 +199,31 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: href="{{ entry.get_absolute_url }}">{{ entry.title }}</a> {% endfor %} +.. function:: page_is_active: + + The advantage of ``page_is_active`` compared to the previous tags is that + it also nows how to handle page pretenders. If ``entry`` is a page + pretender, the template tag returns ``True`` if the current path starts + with the page pretender's path. If ``entry`` is a regular page, the logic + is the same as in ``is_equal_or_parent_of``. + + :: + + {% load feincms_page_tags %} + {% feincms_nav feincms_page level=1 as main %} + {% for entry in main %} + {% page_is_active entry as is_active %} + <a {% if is_active %}class="mark"{% endif %} + href="{{ entry.get_absolute_url }}">{{ entry.title }}</a> + {% endfor %} + + The values of ``feincms_page`` (the current page) and the current path + are pulled out of the context variables ``feincms_page`` and ``request``. + They can also be overriden if you so require:: + + {% page_is_active entry feincms_page=something path=request.path %} + + Application content template tags ================================= From 1fe7823e4acc947c890c9230ae5fc8c993ab0151 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 12:43:57 +0100 Subject: [PATCH 0893/1590] Remove an unneeded environment variable from tox.ini --- tests/tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/tox.ini b/tests/tox.ini index 8660e80b6..10b57f83a 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -18,7 +18,6 @@ commands = {envpython} manage.py test {posargs:testapp} --settings=testapp.settings setenv = PYTHONPATH = .:{toxworkdir}/../.. - FEINCMS_RUN_TESTS = 1 [testenv:py26-1.4.X] basepython = python2.6 From 132f5c715d2b71eb08feb56ff31830ab2ffe9ebc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 12:45:37 +0100 Subject: [PATCH 0894/1590] ... --- feincms/module/page/templatetags/feincms_page_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 503f53d58..1136ba618 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -491,8 +491,8 @@ def siblings_along_path_to(page_list, page2): return () -# ------------------------------------------------------------------------ +# ------------------------------------------------------------------------ @register.assignment_tag(takes_context=True) def page_is_active(context, page, feincms_page=None, path=None): """ From 1b01462688af89a7ce0f1a2f912a9be7e9a23691 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 29 Nov 2013 17:14:39 +0100 Subject: [PATCH 0895/1590] Avoid calling recolorRows() for each closed node in a tree_editor. Together with a slowness probably due to recent update to jquery, this resulted in terrible page tree rendering times (around 40s for 400 pages). Instead of simulating a click on the row, just call the row handler directly and recolor everything afterwards. Also speed up recolorRows() x5 by rearranging and caching some selector results. --- feincms/static/feincms/tree_editor.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/feincms/static/feincms/tree_editor.js b/feincms/static/feincms/tree_editor.js index 46016b4e9..1116e6c62 100755 --- a/feincms/static/feincms/tree_editor.js +++ b/feincms/static/feincms/tree_editor.js @@ -20,8 +20,10 @@ feincms.jQuery(function($){ /* Mark inactive rows */ $('tr.item_inactive').removeClass('item_inactive'); - $('div[id^=wrap_active_] input:checkbox:not(:checked)').parents('tr').addClass('item_inactive'); - $('div[id^=wrap_active_] img').parents('tr').addClass('item_inactive'); + var in_wrap_active = $('div[id^=wrap_active_]'); + var in_wrap_input = $('input', in_wrap_active); + $(':checkbox:not(:checked)', in_wrap_input).parents('tr').addClass('item_inactive'); + $('img', in_wrap_active).parents('tr').addClass('item_inactive'); }); $(document.body).on('click', '[data-inplace]', function() { @@ -303,13 +305,12 @@ feincms.jQuery(function($){ storeCollapsedNodes(feincms.collapsed_nodes); doToggle(itemId, show); - - $('#result_list tbody').recolorRows(); } $.extend($.fn.feinTreeToggleItem = function() { $(this).click(function(event){ expandOrCollapseNode($(this)); + $('#result_list tbody').recolorRows(); if(event.stopPropagation) { event.stopPropagation(); } else { @@ -423,7 +424,7 @@ feincms.jQuery(function($){ $('#collapse_entire_tree').click(); } else { for(var i=0; i<storedNodes.length; i++) { - $('#page_marker-' + storedNodes[i]).click(); + expandOrCollapseNode($('#page_marker-' + storedNodes[i])); } } } From 1e87ec4cc74e2036038bb598e6d5e9d57dd40016 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 29 Nov 2013 17:25:09 +0100 Subject: [PATCH 0896/1590] Add missing row recoloring after expanding items with keyboard. --- feincms/static/feincms/tree_editor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/static/feincms/tree_editor.js b/feincms/static/feincms/tree_editor.js index 1116e6c62..e2284dd1b 100755 --- a/feincms/static/feincms/tree_editor.js +++ b/feincms/static/feincms/tree_editor.js @@ -387,6 +387,7 @@ feincms.jQuery(function($){ case 37: // left case 39: // right expandOrCollapseNode($(this).find('.page_marker')); + $('#result_list tbody').recolorRows(); break; case 13: // return where_to = extractItemId($('span', this).attr('id')); From 67d38e5a37e414e5c98a1bcb7c90ee357bbea1a7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 16:15:09 +0100 Subject: [PATCH 0897/1590] Stop gitting in quickstart.sh --- quickstart.sh | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/quickstart.sh b/quickstart.sh index f94b8dfac..c65d8b233 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -3,21 +3,15 @@ # This script downloads all the software needed to run FeinCMS # -echo "Downloading Django and django-mptt via git... (this will take some time)" - -mkdir lib -cd lib -git clone git://github.com/django/django.git -git clone git://github.com/django-mptt/django-mptt.git -cd .. -ln -s lib/django/django django -ln -s lib/django-mptt/mptt mptt +cd example +virtualenv venv +. venv/bin/activate +pip install Django django-mptt Pillow cat <<EOD Everything should be ready now. Type the following commands into the shell to start the test server: -cd example python manage.py runserver Navigate to http://127.0.0.1:8000/admin/ to see the admin interface. The From c16c2f00b356db93569ef67119f27fe4e56080f2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 29 Nov 2013 20:25:10 +0100 Subject: [PATCH 0898/1590] Commit a management command to generate big page trees --- example/management/__init__.py | 0 example/management/commands/__init__.py | 0 .../management/commands/generate_big_tree.py | 51 +++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 example/management/__init__.py create mode 100644 example/management/commands/__init__.py create mode 100644 example/management/commands/generate_big_tree.py diff --git a/example/management/__init__.py b/example/management/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/example/management/commands/__init__.py b/example/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/example/management/commands/generate_big_tree.py b/example/management/commands/generate_big_tree.py new file mode 100644 index 000000000..b9a2a15f4 --- /dev/null +++ b/example/management/commands/generate_big_tree.py @@ -0,0 +1,51 @@ +# ------------------------------------------------------------------------ +# coding=utf-8 +# ------------------------------------------------------------------------ + +from __future__ import print_function + +from django.core.management.base import NoArgsCommand + +from feincms.module.page.models import Page + + +class Command(NoArgsCommand): + help = ( + "Run this command to generate a big tree for performance testing" + " purposes.") + + def handle_noargs(self, **options): + parents = [None] * 5 + + Page.objects.all().delete() + + for i1 in range(5): + parents[0] = Page.objects.create( + title='Page %s' % (i1,), + ) + + for i2 in range(5): + parents[1] = Page.objects.create( + title='Page %s.%s' % (i1, i2), + parent=parents[0], + ) + + for i3 in range(5): + parents[2] = Page.objects.create( + title='Page %s.%s.%s' % (i1, i2, i3), + parent=parents[1], + ) + + for i4 in range(5): + parents[3] = Page.objects.create( + title='Page %s.%s.%s.%s' % (i1, i2, i3, i4), + parent=parents[2], + ) + + print(parents) + + #for i5 in range(5): + #parents[4] = Page.objects.create( + #title='Page %s.%s.%s.%s.%s' % (i1, i2, i3, i4, i5), + #parent=parents[3], + #) From afaef87a90c1914488dd670f024775c480270604 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 30 Nov 2013 14:34:22 +0100 Subject: [PATCH 0899/1590] Remove a few gendered pronouns Fixes #499 for now. --- docs/advanced/designdecisions.rst | 8 ++++---- feincms/module/extensions/translations.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/advanced/designdecisions.rst b/docs/advanced/designdecisions.rst index 164bc9d63..420410989 100644 --- a/docs/advanced/designdecisions.rst +++ b/docs/advanced/designdecisions.rst @@ -18,8 +18,8 @@ them using a lightbox script or something similar? You have to resort to writing loads of JavaScript code which will only work on one browser. You cannot really filter the HTML code generated by the user to kick out ugly HTML code generated by copy-pasting from word. The -user will upload 10mb JPEGs and resize them to 50x50 pixels by -himself. +user will upload 10mb JPEGs and resize them to 50x50 pixels in the rich +text editor. All of this convinced me that offering the user a rich text editor with too much capabilities is a really bad idea. The rich text editor @@ -27,8 +27,8 @@ in FeinCMS only has bold, italic, bullets, link and headlines activated (and the HTML code button, because that's sort of inevitable -- sometimes the rich text editor messes up and you cannot fix it other than going directly into the HTML code. Plus, if someone really -knows what he's doing, I'd still like to give him the power to shot -his own foot). +knows what he's doing, I'd still like to give them the power to shot +their own foot). If this does not seem convincing you can always add your own rich text content type with a different configuration (or just override the rich diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index eda73162a..6ace3fb7f 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -73,7 +73,7 @@ def translation_set_language(request, select_language): request.session['django_language'] = select_language elif request.method == 'GET' and not fallback: # No session is active. We need to set a cookie for the language - # so that it persists when the user changes his location to somewhere + # so that it persists when users change their location to somewhere # not under the control of the CMS. # Only do this when request method is GET (mainly, do not abort # POST requests) @@ -97,7 +97,7 @@ def translations_request_processor_explicit(page, request): if 'set_language' in request.GET: desired_language = request.GET['set_language'] # ...or the user already has explicitely set a language, bail out and - # don't change it for him behind her back + # don't change it for them behind their back elif user_has_language_set(request): return From 599e7b8a8e56a2d7873374443f293d440aaf54ff Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 30 Nov 2013 14:54:13 +0100 Subject: [PATCH 0900/1590] Use event delegation instead of binding the click event of all span.page_marker elements Refs #498. --- feincms/static/feincms/tree_editor.js | 32 ++++++++++++--------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/feincms/static/feincms/tree_editor.js b/feincms/static/feincms/tree_editor.js index e2284dd1b..9c176dfd2 100755 --- a/feincms/static/feincms/tree_editor.js +++ b/feincms/static/feincms/tree_editor.js @@ -307,21 +307,6 @@ feincms.jQuery(function($){ doToggle(itemId, show); } - $.extend($.fn.feinTreeToggleItem = function() { - $(this).click(function(event){ - expandOrCollapseNode($(this)); - $('#result_list tbody').recolorRows(); - if(event.stopPropagation) { - event.stopPropagation(); - } else { - event.cancelBubble = true; - } - - return false; - }); - return this; - }); - // bind the collapse all children event $.extend($.fn.bindCollapseTreeEvent = function() { $(this).click(function() { @@ -399,11 +384,22 @@ feincms.jQuery(function($){ } // fire! - var rlist = $("#result_list"); + var rlist = $("#result_list"), + rlist_tbody = rlist.find('tbody'); + if($('tbody tr', rlist).length > 1) { rlist.hide(); - $('tbody', rlist).feinTree(); - $('span.page_marker', rlist).feinTreeToggleItem(); + rlist_tbody.feinTree(); + + rlist.on('click', 'span.page_marker', function(event) { + event.preventDefault(); + event.stopPropagation(); + + expandOrCollapseNode($(this)); + + rlist_tbody.recolorRows(); + }); + $('#collapse_entire_tree').bindCollapseTreeEvent(); $('#open_entire_tree').bindOpenTreeEvent(); From 6fa96bf07764dcc637729c0b5c25af550f7ad012 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 30 Nov 2013 15:09:27 +0100 Subject: [PATCH 0901/1590] FeinCMS v1.9.0 --- docs/releases/1.9.rst | 6 +++--- feincms/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index 0134d8097..ed0d4a2fb 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -1,6 +1,6 @@ -==================================== -FeinCMS 1.9 release notes (upcoming) -==================================== +========================= +FeinCMS 1.9 release notes +========================= Welcome to FeinCMS 1.9! diff --git a/feincms/__init__.py b/feincms/__init__.py index 7ba632a84..dce658e40 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 9, 0, 'pre') +VERSION = (1, 9, 0) __version__ = '.'.join(map(str, VERSION)) From 3a75e57486de3f669343bceb63e0fde6c42d15ee Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 4 Dec 2013 16:00:16 +0100 Subject: [PATCH 0902/1590] JSONField: (Hopefully) fix a real-life crash we've been seeing We should probably rename JSONField to JSONDictField, because we only support dictionaries inside. --- feincms/contrib/fields.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 81afb7640..effdb9c08 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -9,7 +9,9 @@ class JSONFormField(forms.fields.CharField): def clean(self, value, *args, **kwargs): - if value: + # It seems that sometimes we receive dict objects here, not only + # strings. Partial form validation maybe? + if value and not isinstance(value, dict): try: # Run the value through JSON so we can normalize formatting # and at least learn about malformed data: From 9f5aa010b8f774e203816c0f4db04ed821da3ae2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 5 Dec 2013 11:51:57 +0100 Subject: [PATCH 0903/1590] Add links to the travis images --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 5a3b9c7e7..a3976e2ba 100644 --- a/README.rst +++ b/README.rst @@ -121,4 +121,6 @@ Travis CI ========= .. image:: https://travis-ci.org/feincms/feincms.png?branch=next + :target: https://travis-ci.org/feincms/feincms .. image:: https://travis-ci.org/feincms/feincms.png?branch=master + :target: https://travis-ci.org/feincms/feincms From 6137e2c5317ef701e79edc40449414e5400bbd35 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 9 Dec 2013 09:38:02 +0100 Subject: [PATCH 0904/1590] JSONField: Only attempt json.loads() on string types during validation --- feincms/contrib/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index effdb9c08..0f31128a9 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -11,7 +11,7 @@ class JSONFormField(forms.fields.CharField): def clean(self, value, *args, **kwargs): # It seems that sometimes we receive dict objects here, not only # strings. Partial form validation maybe? - if value and not isinstance(value, dict): + if value and isinstance(value, six.string_types): try: # Run the value through JSON so we can normalize formatting # and at least learn about malformed data: From e2b698599b07ba7774ac85e70408a7c0791b9ba6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 9 Dec 2013 10:32:39 +0100 Subject: [PATCH 0905/1590] JSONFormField.clean should return a string --- feincms/contrib/fields.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 0f31128a9..92ffe635f 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -11,11 +11,17 @@ class JSONFormField(forms.fields.CharField): def clean(self, value, *args, **kwargs): # It seems that sometimes we receive dict objects here, not only # strings. Partial form validation maybe? - if value and isinstance(value, six.string_types): + if value: + if isinstance(value, six.string_types): + try: + value = json.loads(value) + except ValueError: + raise forms.ValidationError("Invalid JSON data!") + try: # Run the value through JSON so we can normalize formatting # and at least learn about malformed data: - value = json.dumps(json.loads(value), cls=DjangoJSONEncoder) + value = json.dumps(value, cls=DjangoJSONEncoder) except ValueError: raise forms.ValidationError("Invalid JSON data!") From 81cdab7602789f2ca3e2cd1f16eb659b4b7c9750 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 9 Dec 2013 10:48:29 +0100 Subject: [PATCH 0906/1590] Big enough --- example/management/commands/generate_big_tree.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/example/management/commands/generate_big_tree.py b/example/management/commands/generate_big_tree.py index b9a2a15f4..c3e6ddf90 100644 --- a/example/management/commands/generate_big_tree.py +++ b/example/management/commands/generate_big_tree.py @@ -43,9 +43,3 @@ def handle_noargs(self, **options): ) print(parents) - - #for i5 in range(5): - #parents[4] = Page.objects.create( - #title='Page %s.%s.%s.%s.%s' % (i1, i2, i3, i4, i5), - #parent=parents[3], - #) From 72a5aaf79e1be613fc261f1af4eb455e6634cf5e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 13 Dec 2013 18:14:49 +0100 Subject: [PATCH 0907/1590] New helper ExtensionModelAdmin.extend_list makes it easier to safely extend model admin list attributes --- feincms/extensions.py | 5 +++++ feincms/module/extensions/seo.py | 5 ++++- feincms/module/extensions/translations.py | 11 ++++++----- feincms/module/page/extensions/relatedpages.py | 4 +--- feincms/module/page/extensions/sites.py | 4 ++-- feincms/module/page/extensions/symlinks.py | 2 +- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index a1df512fa..143a7a5a1 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -124,6 +124,11 @@ def add_extension_options(self, *f): # XXX This is really messy. self.fieldsets[0][1]['fields'].extend(f) + def extend_list(self, attribute, iterable): + extended = list(getattr(self, attribute, ())) + extended.extend(iterable) + setattr(self, attribute, extended) + def prefetch_modeladmin_get_queryset(modeladmin, *lookups): """ diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index 4bf689a63..868f1f32c 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -22,7 +22,10 @@ def handle_model(self): 'Text longer than 140 characters is truncated.'))) def handle_modeladmin(self, modeladmin): - modeladmin.search_fields.extend(['meta_keywords', 'meta_description']) + modeladmin.extend_list( + 'search_fields', + ['meta_keywords', 'meta_description'], + ) modeladmin.add_extension_options(_('Search engine optimization'), { 'fields': ('meta_keywords', 'meta_description'), diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 6ace3fb7f..131ef677c 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -256,10 +256,11 @@ def available_translations_admin(self, page): if hasattr(modeladmin, 'add_extension_options'): modeladmin.add_extension_options('language', 'translation_of') - modeladmin.list_display.extend( - ['language', 'available_translations_admin']) - modeladmin.list_filter.extend(['language']) - - modeladmin.raw_id_fields.append('translation_of') + modeladmin.extend_list( + 'list_display', + ['language', 'available_translations_admin'], + ) + modeladmin.extend_list('list_filter', ['language']) + modeladmin.extend_list('raw_id_fields', ['translation_of']) # ------------------------------------------------------------------------ diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 43f5411ab..4a3009c94 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -19,9 +19,7 @@ def handle_model(self): 'Select pages that should be listed as related content.'))) def handle_modeladmin(self, modeladmin): - modeladmin.filter_horizontal = list( - getattr(modeladmin, 'filter_horizontal', ())) - modeladmin.filter_horizontal.append('related_pages') + modeladmin.extend_list('filter_horizontal', ['related_pages']) modeladmin.add_extension_options(_('Related pages'), { 'fields': ('related_pages',), diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index 93e510c89..b70f1933f 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -21,6 +21,6 @@ def handle_model(self): PageManager.add_to_active_filters(current_site, key='current_site') def handle_modeladmin(self, modeladmin): - modeladmin.list_display.extend(['site']) - modeladmin.list_filter.extend(['site']) + modeladmin.extend_list('list_display', ['site']) + modeladmin.extend_list('list_filter', ['site']) modeladmin.add_extension_options('site') diff --git a/feincms/module/page/extensions/symlinks.py b/feincms/module/page/extensions/symlinks.py index 4e5e2d82f..41fb5dcb8 100644 --- a/feincms/module/page/extensions/symlinks.py +++ b/feincms/module/page/extensions/symlinks.py @@ -32,5 +32,5 @@ def content(self): return self._content_proxy def handle_modeladmin(self, modeladmin): - modeladmin.raw_id_fields.append('symlinked_page') + modeladmin.extend_list('raw_id_fields', ['symlinked_page']) modeladmin.add_extension_options('symlinked_page') From 95fa42fd7569ab812bbd9f1dd81dffecd522063f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Fri, 13 Dec 2013 18:22:50 +0100 Subject: [PATCH 0908/1590] FeinCMS v1.9.1 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index dce658e40..b881abb13 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 9, 0) +VERSION = (1, 9, 1) __version__ = '.'.join(map(str, VERSION)) From e670e114893640361d2623e26269ed4935b5a68d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 22 Dec 2013 17:39:57 +0100 Subject: [PATCH 0909/1590] Make the tests pass with Django@master; hopefully we can remove all of it when Django 1.7 arrives --- feincms/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index b881abb13..fac53dfb7 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -74,7 +74,8 @@ def ensure_completely_loaded(force=False): # get_models cache again here. If we don't do this, Django 1.5 chokes on # a model validation error (Django 1.4 doesn't exhibit this problem). # See Issue #323 on github. - loading.cache._get_models_cache.clear() + if hasattr(loading, 'cache'): + loading.cache._get_models_cache.clear() if loading.app_cache_ready(): COMPLETELY_LOADED = True From 0495e00a058301b8539ce32723e89fd4f0bd3af9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 30 Dec 2013 20:27:08 +0100 Subject: [PATCH 0910/1590] unicode_literals everything, add tox configuration for running the tests with Python 3.2 --- feincms/__init__.py | 2 ++ feincms/_internal.py | 2 ++ feincms/admin/filterspecs.py | 2 ++ feincms/admin/item_editor.py | 4 ++- feincms/admin/tree_editor.py | 2 ++ feincms/content/application/models.py | 2 ++ feincms/content/comments/models.py | 2 ++ feincms/content/contactform/models.py | 2 ++ feincms/content/file/models.py | 2 ++ feincms/content/image/models.py | 2 ++ feincms/content/medialibrary/models.py | 2 ++ feincms/content/raw/models.py | 2 ++ feincms/content/richtext/models.py | 2 ++ feincms/content/rss/models.py | 2 ++ feincms/content/section/models.py | 2 ++ feincms/content/template/models.py | 2 ++ feincms/content/video/models.py | 2 ++ feincms/contrib/fields.py | 2 ++ feincms/contrib/preview/views.py | 2 ++ feincms/contrib/richtext.py | 2 ++ feincms/contrib/tagging.py | 2 +- feincms/default_settings.py | 2 ++ feincms/extensions.py | 2 ++ feincms/management/checker.py | 2 +- .../management/commands/feincms_validate.py | 2 +- .../commands/medialibrary_orphans.py | 2 +- feincms/management/commands/rebuild_mptt.py | 3 +- .../management/commands/update_rsscontent.py | 2 ++ feincms/models.py | 4 ++- feincms/module/blog/extensions/tags.py | 2 ++ .../module/blog/extensions/translations.py | 2 ++ feincms/module/blog/models.py | 2 ++ feincms/module/extensions/changedate.py | 2 ++ feincms/module/extensions/ct_tracker.py | 2 ++ feincms/module/extensions/datepublisher.py | 2 ++ feincms/module/extensions/featured.py | 2 ++ feincms/module/extensions/seo.py | 2 ++ feincms/module/extensions/translations.py | 2 ++ feincms/module/medialibrary/admin.py | 2 +- feincms/module/medialibrary/fields.py | 2 +- feincms/module/medialibrary/forms.py | 2 +- feincms/module/medialibrary/modeladmins.py | 2 +- feincms/module/medialibrary/models.py | 2 +- feincms/module/medialibrary/thumbnail.py | 2 ++ feincms/module/medialibrary/zip.py | 2 +- feincms/module/mixins.py | 2 ++ feincms/module/page/admin.py | 2 +- feincms/module/page/extensions/excerpt.py | 2 ++ feincms/module/page/extensions/navigation.py | 2 ++ .../module/page/extensions/relatedpages.py | 2 ++ feincms/module/page/extensions/sites.py | 2 ++ feincms/module/page/extensions/symlinks.py | 2 ++ feincms/module/page/extensions/titles.py | 2 ++ feincms/module/page/forms.py | 2 +- feincms/module/page/modeladmins.py | 2 +- feincms/module/page/models.py | 2 ++ feincms/module/page/processors.py | 2 +- feincms/module/page/sitemap.py | 2 ++ .../page/templatetags/feincms_page_tags.py | 2 ++ feincms/shortcuts.py | 2 ++ feincms/signals.py | 2 ++ .../templatetags/applicationcontent_tags.py | 2 ++ feincms/templatetags/feincms_admin_tags.py | 2 ++ feincms/templatetags/feincms_tags.py | 2 ++ feincms/templatetags/feincms_thumbnail.py | 2 ++ feincms/templatetags/fragment_tags.py | 2 ++ feincms/translations.py | 5 ++- feincms/utils/__init__.py | 2 +- feincms/utils/html/tidy.py | 2 ++ feincms/utils/managers.py | 3 ++ feincms/utils/queryset_transform.py | 2 ++ feincms/utils/templatetags.py | 2 ++ feincms/views/cbv/views.py | 2 ++ feincms/views/decorators.py | 2 ++ tests/tox.ini | 33 +++++++++++++++++++ 75 files changed, 171 insertions(+), 19 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index fac53dfb7..d45999052 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + VERSION = (1, 9, 1) __version__ = '.'.join(map(str, VERSION)) diff --git a/feincms/_internal.py b/feincms/_internal.py index 8e13f2594..5109a9d32 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -4,6 +4,8 @@ http://mail.python.org/pipermail/python-dev/2008-January/076194.html """ +from __future__ import absolute_import, unicode_literals + def monkeypatch_method(cls): """ diff --git a/feincms/admin/filterspecs.py b/feincms/admin/filterspecs.py index fda501965..f189927f1 100644 --- a/feincms/admin/filterspecs.py +++ b/feincms/admin/filterspecs.py @@ -4,6 +4,8 @@ # Authors: Marinho Brandao <marinho at gmail.com> # Guilherme M. Gondim (semente) <semente at taurinus.org> +from __future__ import absolute_import, unicode_literals + from django.contrib.admin.filters import ( FieldListFilter, ChoicesFieldListFilter) from django.utils import six diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index da0b7e75d..59c50119d 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + import copy import logging import re @@ -122,7 +124,7 @@ def get_feincms_inlines(self, model, request): name = '%sFeinCMSInline' % content_type.__name__ # TODO: We generate a new class every time. Is that really wanted? - inline_class = type(name, (inline,), attrs) + inline_class = type(str(name), (inline,), attrs) inlines.append(inline_class) return inlines diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 7d3ae0e6c..ab22c5031 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + from functools import reduce import json import logging diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 38a9d9d74..a4ca3e415 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -2,6 +2,8 @@ Third-party application inclusion support. """ +from __future__ import absolute_import, unicode_literals + from email.utils import parsedate from time import mktime from random import SystemRandom diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index 66335c8dd..e36dc3182 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -12,6 +12,8 @@ ``django.contrib.comments`` application. """ +from __future__ import absolute_import, unicode_literals + from django.contrib import comments from django.contrib.comments.views.comments import post_comment from django.db import models diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index d669f010b..f5c68c2c4 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -5,6 +5,8 @@ ``form=YourClass`` argument to the ``create_content_type`` call. """ +from __future__ import absolute_import, unicode_literals + from django import forms from django.core.mail import send_mail from django.db import models diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index 105158250..5b86d9f95 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -3,6 +3,8 @@ instead. """ +from __future__ import absolute_import, unicode_literals + import os from django.db import models diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index 47a12c461..69ff2da2d 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -3,6 +3,8 @@ instead. """ +from __future__ import absolute_import, unicode_literals + import os from django.db import models diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 396dd50a8..43545662c 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + from django.contrib import admin from django.core.exceptions import ImproperlyConfigured from django.db import models diff --git a/feincms/content/raw/models.py b/feincms/content/raw/models.py index 827d08247..487c5a241 100644 --- a/feincms/content/raw/models.py +++ b/feincms/content/raw/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 7f8bdc4b7..b72d46861 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django import forms from django.core.exceptions import ImproperlyConfigured from django.db import models diff --git a/feincms/content/rss/models.py b/feincms/content/rss/models.py index e7fcc3ff6..70353d1af 100644 --- a/feincms/content/rss/models.py +++ b/feincms/content/rss/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + import time from django.db import models diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index f9a26ed3e..88516290a 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django.conf import settings as django_settings from django.contrib import admin from django.core.exceptions import ImproperlyConfigured diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 31e9190ec..a2b1e2b72 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + import os from django.db import models diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index f84f6e161..b650aa21a 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + import re from django.db import models diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 92ffe635f..f69b3baa9 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + import json import logging diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index 1d81f07ac..c8486d651 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django.http import Http404 from django.shortcuts import get_object_or_404 diff --git a/feincms/contrib/richtext.py b/feincms/contrib/richtext.py index 89ad29f8a..5ad17559c 100644 --- a/feincms/contrib/richtext.py +++ b/feincms/contrib/richtext.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django import forms from django.db import models diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index e26cfef99..3bd2dc848 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -8,7 +8,7 @@ # tagging.tag_model(Page) # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 6db7eb510..61861761b 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -8,6 +8,8 @@ ``settings.py`` file. """ +from __future__ import absolute_import, unicode_literals + from os.path import join from django.conf import settings diff --git a/feincms/extensions.py b/feincms/extensions.py index 143a7a5a1..5a31ac648 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -2,6 +2,8 @@ Base types for extensions refactor """ +from __future__ import absolute_import, unicode_literals + from functools import wraps import inspect diff --git a/feincms/management/checker.py b/feincms/management/checker.py index fcecd139d..27330efe4 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -1,4 +1,4 @@ -from __future__ import print_function +from __future__ import absolute_import, print_function, unicode_literals from django.core.management.color import color_style from django.db import connection diff --git a/feincms/management/commands/feincms_validate.py b/feincms/management/commands/feincms_validate.py index ad0586ba4..dbf681b9b 100644 --- a/feincms/management/commands/feincms_validate.py +++ b/feincms/management/commands/feincms_validate.py @@ -7,7 +7,7 @@ ``feincms_validate`` checks your models for common pitfalls. """ -from __future__ import print_function +from __future__ import absolute_import, print_function, unicode_literals from django.core.management.base import NoArgsCommand from django.core.management.color import color_style diff --git a/feincms/management/commands/medialibrary_orphans.py b/feincms/management/commands/medialibrary_orphans.py index 19997218a..599c910e6 100644 --- a/feincms/management/commands/medialibrary_orphans.py +++ b/feincms/management/commands/medialibrary_orphans.py @@ -1,4 +1,4 @@ -from __future__ import print_function +from __future__ import absolute_import, print_function, unicode_literals import os diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index e61500935..7258bf9da 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -7,7 +7,8 @@ ``rebuild_mptt`` rebuilds your mptt pointers. Only use in emergencies. """ -from __future__ import print_function + +from __future__ import absolute_import, print_function, unicode_literals from django.core.management.base import NoArgsCommand diff --git a/feincms/management/commands/update_rsscontent.py b/feincms/management/commands/update_rsscontent.py index 78e641174..24a37d12a 100644 --- a/feincms/management/commands/update_rsscontent.py +++ b/feincms/management/commands/update_rsscontent.py @@ -7,6 +7,8 @@ feed by itself. """ +from __future__ import absolute_import, unicode_literals + from django.core.management.base import BaseCommand from feincms.content.rss.models import RSSContent diff --git a/feincms/models.py b/feincms/models.py index bef21510a..baf0cd68c 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -5,6 +5,8 @@ the feincms\_ namespace. """ +from __future__ import absolute_import, unicode_literals + from functools import reduce import sys import operator @@ -548,7 +550,7 @@ def get_queryset(cls, filter_args): RuntimeWarning) cls._feincms_content_model = python_2_unicode_compatible( - type(name, (models.Model,), attrs)) + type(str(name), (models.Model,), attrs)) # list of concrete content types cls._feincms_content_types = [] diff --git a/feincms/module/blog/extensions/tags.py b/feincms/module/blog/extensions/tags.py index 5df1fa143..45731f552 100644 --- a/feincms/module/blog/extensions/tags.py +++ b/feincms/module/blog/extensions/tags.py @@ -2,6 +2,8 @@ Simple tagging support using ``django-tagging``. """ +from __future__ import absolute_import, unicode_literals + from django.utils.translation import ugettext_lazy as _ from feincms import extensions diff --git a/feincms/module/blog/extensions/translations.py b/feincms/module/blog/extensions/translations.py index 704ef4788..e4d8c9bf0 100644 --- a/feincms/module/blog/extensions/translations.py +++ b/feincms/module/blog/extensions/translations.py @@ -6,6 +6,8 @@ thereby enabling deeplinks between translated blog entries. """ +from __future__ import absolute_import, unicode_literals + from django.conf import settings from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index 0662ee734..fb578145b 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -5,6 +5,8 @@ It does work, though. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.db.models import signals from django.utils import timezone diff --git a/feincms/module/extensions/changedate.py b/feincms/module/extensions/changedate.py index 407570548..1af2e3632 100644 --- a/feincms/module/extensions/changedate.py +++ b/feincms/module/extensions/changedate.py @@ -5,6 +5,8 @@ Track the modification date for objects. """ +from __future__ import absolute_import, unicode_literals + from email.utils import parsedate_tz, mktime_tz from django.db import models diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index d889d8d62..05ef06f40 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -17,6 +17,8 @@ saving time, thus saving at least one DB query on page delivery. """ +from __future__ import absolute_import, unicode_literals + from django.contrib.contenttypes.models import ContentType from django.db.models.signals import class_prepared, post_save, pre_save from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index a6f392297..d8ef8eb81 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -8,6 +8,8 @@ """ # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + from datetime import datetime from django.db import models diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index 39ae62bc2..6930a58a7 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -2,6 +2,8 @@ Add a "featured" field to objects so admins can better direct top content. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index 868f1f32c..f71d9f5f3 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -2,6 +2,8 @@ Add a keyword and a description field which are helpful for SEO optimization. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 131ef677c..2a37f0d78 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -15,6 +15,8 @@ as Django's administration tool. """ +from __future__ import absolute_import, unicode_literals + # ------------------------------------------------------------------------ import logging diff --git a/feincms/module/medialibrary/admin.py b/feincms/module/medialibrary/admin.py index 87bd942f6..922450af9 100644 --- a/feincms/module/medialibrary/admin.py +++ b/feincms/module/medialibrary/admin.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals from django.contrib import admin diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index a8ec5aef2..85e44dacf 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals from django.contrib.admin.widgets import AdminFileWidget from django.contrib.admin.widgets import ForeignKeyRawIdWidget diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 38d5f6425..fc598f6c5 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals import os diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 2ac1fa25f..82cb63608 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals import os diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 3f4f54221..fa766b834 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals import os import re diff --git a/feincms/module/medialibrary/thumbnail.py b/feincms/module/medialibrary/thumbnail.py index 577e0fcad..a70c2dc27 100644 --- a/feincms/module/medialibrary/thumbnail.py +++ b/feincms/module/medialibrary/thumbnail.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from feincms import settings from feincms.templatetags import feincms_thumbnail from feincms.utils import get_object diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index d4a8109b9..d563658f3 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -7,7 +7,7 @@ # # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals import json import zipfile diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 4b7299351..b9d2d8303 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django.http import Http404 from django.template import Template from django.utils.datastructures import SortedDict diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index 40fb38fd2..4abea4668 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals from django.contrib import admin from django.core.exceptions import ImproperlyConfigured diff --git a/feincms/module/page/extensions/excerpt.py b/feincms/module/page/extensions/excerpt.py index e35d0266f..25fe9004a 100644 --- a/feincms/module/page/extensions/excerpt.py +++ b/feincms/module/page/extensions/excerpt.py @@ -2,6 +2,8 @@ Add an excerpt field to the page. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 591fe0071..c64ec0362 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -7,6 +7,8 @@ be they real Page instances or extended navigation entries. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils import six from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 4a3009c94..a8be7500f 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -2,6 +2,8 @@ Add a many-to-many relationship field to relate this page to other pages. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index b70f1933f..536df8710 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django.conf import settings from django.contrib.sites.models import Site from django.db import models diff --git a/feincms/module/page/extensions/symlinks.py b/feincms/module/page/extensions/symlinks.py index 41fb5dcb8..321f2cc48 100644 --- a/feincms/module/page/extensions/symlinks.py +++ b/feincms/module/page/extensions/symlinks.py @@ -3,6 +3,8 @@ all content from the linked page. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index 7cc5efa6e..5ce3f038f 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -4,6 +4,8 @@ you do that. """ +from __future__ import absolute_import, unicode_literals + from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 6bd8c5859..81046771e 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals import re diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 8df776db9..ace81d8fa 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals from django.conf import settings as django_settings from django.core.exceptions import PermissionDenied diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 11a7cd283..9f77fbb78 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + import re from django.core.cache import cache as django_cache diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 722f81182..104d4a97a 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -1,4 +1,4 @@ -from __future__ import print_function +from __future__ import absolute_import, print_function, unicode_literals import re import sys diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index b53f2dbe0..7a56314e8 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + from django.db.models import Max from django.db.models import get_model from django.contrib.sitemaps import Sitemap diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 1136ba618..0997dd076 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + import logging import sys import traceback diff --git a/feincms/shortcuts.py b/feincms/shortcuts.py index 367141159..adb47aa4e 100644 --- a/feincms/shortcuts.py +++ b/feincms/shortcuts.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django.shortcuts import render_to_response from django.template import RequestContext diff --git a/feincms/signals.py b/feincms/signals.py index b921bc0e2..2d4fca135 100644 --- a/feincms/signals.py +++ b/feincms/signals.py @@ -7,6 +7,8 @@ # # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + from django.dispatch import Signal # ------------------------------------------------------------------------ diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index 7da297124..a4c6d435a 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django import template from django.core.urlresolvers import NoReverseMatch from django.template import TemplateSyntaxError diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py index 2ada605d3..ce944f01a 100644 --- a/feincms/templatetags/feincms_admin_tags.py +++ b/feincms/templatetags/feincms_admin_tags.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + import django from django import template diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index e3a64aef5..23ce93746 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + import logging from django import template diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 361cdeafc..ddf2d7992 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + from io import BytesIO import re diff --git a/feincms/templatetags/fragment_tags.py b/feincms/templatetags/fragment_tags.py index 2234ef2e3..7cf8dabaf 100644 --- a/feincms/templatetags/fragment_tags.py +++ b/feincms/templatetags/fragment_tags.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django import template diff --git a/feincms/translations.py b/feincms/translations.py index 537256b68..a540471e8 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -28,6 +28,8 @@ class NewsTranslation(Translation(News)): print news.translation.title """ +from __future__ import absolute_import, unicode_literals + from django.conf import settings from django.contrib import admin from django.core.cache import cache @@ -320,4 +322,5 @@ def admin_translationinline(model, inline_class=admin.StackedInline, **kwargs): kwargs['extra'] = 1 kwargs['max_num'] = len(settings.LANGUAGES) kwargs['model'] = model - return type(model.__class__.__name__ + 'Inline', (inline_class,), kwargs) + return type( + str(model.__class__.__name__ + 'Inline'), (inline_class,), kwargs) diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 545114aa8..236bbe626 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import division +from __future__ import absolute_import, division, unicode_literals try: from hashlib import md5 diff --git a/feincms/utils/html/tidy.py b/feincms/utils/html/tidy.py index c5b97aaa7..130cf393c 100644 --- a/feincms/utils/html/tidy.py +++ b/feincms/utils/html/tidy.py @@ -1,5 +1,7 @@ # encoding: utf-8 +from __future__ import absolute_import, unicode_literals + import re import tidylib diff --git a/feincms/utils/managers.py b/feincms/utils/managers.py index 0a7cd727c..63d7e9f8f 100644 --- a/feincms/utils/managers.py +++ b/feincms/utils/managers.py @@ -1,3 +1,6 @@ +from __future__ import absolute_import, unicode_literals + + # ------------------------------------------------------------------------ class ActiveAwareContentManagerMixin(object): """ diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 70d33c3d5..0e26092ab 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -81,6 +81,8 @@ def lookup_tags(item_qs): SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ +from __future__ import absolute_import, unicode_literals + from django.db import models diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index 26f4d2838..347d74b55 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -9,6 +9,8 @@ {% tag of template_var as var_name arg1,arg2,kwarg3=4 %} ''' +from __future__ import absolute_import, unicode_literals + from django import template diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 6c78384a7..905469e0e 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django.db.models import get_model from django.http import Http404 diff --git a/feincms/views/decorators.py b/feincms/views/decorators.py index baaf8db08..7a6377ce9 100644 --- a/feincms/views/decorators.py +++ b/feincms/views/decorators.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from functools import wraps from django.http import HttpResponse diff --git a/tests/tox.ini b/tests/tox.ini index 10b57f83a..2be18e98c 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -9,6 +9,9 @@ envlist = py27-1.5.X, py27-1.6.X, py27-1.7.X, + py32-1.5.X, + py32-1.6.X, + py32-1.7.X, py33-1.5.X, py33-1.6.X, py33-1.7.X, @@ -89,6 +92,36 @@ deps = lxml==3.2.3 BeautifulSoup==3.2.1 +[testenv:py32-1.5.X] +basepython = python3.2 +deps = + Django==1.5.4 + django-mptt==0.6.0 + Pillow==2.2.1 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 + +[testenv:py32-1.6.X] +basepython = python3.2 +deps = + Django==1.6.0 + django-mptt==0.6.0 + Pillow==2.2.1 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 + +[testenv:py32-1.7.X] +basepython = python3.2 +deps = + --editable=git+git://github.com/django/django.git@master#egg=django-dev + django-mptt==0.6.0 + Pillow==2.2.1 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 + [testenv:py33-1.5.X] basepython = python3.3 deps = From e92e0843ee3f3b0553344942b795d888ee1c413e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 30 Dec 2013 20:53:51 +0100 Subject: [PATCH 0911/1590] Remove "u" string prefixes --- feincms/admin/item_editor.py | 2 +- feincms/admin/tree_editor.py | 12 +++++----- feincms/content/application/models.py | 2 +- feincms/content/comments/models.py | 6 ++--- feincms/content/contactform/models.py | 2 +- feincms/content/template/models.py | 2 +- feincms/contrib/tagging.py | 2 +- feincms/management/checker.py | 4 ++-- feincms/models.py | 10 ++++----- .../module/blog/extensions/translations.py | 4 ++-- feincms/module/extensions/datepublisher.py | 2 +- feincms/module/extensions/translations.py | 10 ++++----- feincms/module/medialibrary/fields.py | 14 ++++++------ feincms/module/medialibrary/modeladmins.py | 8 +++---- feincms/module/medialibrary/models.py | 14 ++++++------ feincms/module/page/extensions/titles.py | 2 +- feincms/module/page/forms.py | 6 ++--- feincms/module/page/modeladmins.py | 12 +++++----- feincms/module/page/models.py | 14 ++++++------ feincms/module/page/processors.py | 4 ++-- .../page/templatetags/feincms_page_tags.py | 4 ++-- .../templatetags/applicationcontent_tags.py | 4 ++-- feincms/templatetags/feincms_tags.py | 4 ++-- feincms/templatetags/feincms_thumbnail.py | 6 ++--- feincms/templatetags/fragment_tags.py | 8 +++---- feincms/translations.py | 6 ++--- feincms/utils/__init__.py | 10 ++++----- tests/testapp/applicationcontent_urls.py | 4 +++- tests/testapp/models.py | 4 +++- tests/testapp/navigation_extensions.py | 2 ++ tests/testapp/settings.py | 2 ++ tests/testapp/tests/test_cms.py | 2 +- tests/testapp/tests/test_extensions.py | 4 ++-- tests/testapp/tests/test_page.py | 22 +++++++++---------- tests/testapp/tests/test_stuff.py | 18 ++++++++------- tests/testapp/urls.py | 2 ++ tests/tox-update-venvs.sh | 4 ++++ 37 files changed, 127 insertions(+), 111 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 59c50119d..86cf750aa 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -88,7 +88,7 @@ def append_feincms_inlines(self, inline_instances, request): inline_instances.append(inline_instance) def can_add_content(self, request, content_type): - perm = u'.'.join(( + perm = '.'.join(( content_type._meta.app_label, content_type._meta.get_add_permission())) return request.user.has_perm(perm) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index ab22c5031..5a427a5e0 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -45,7 +45,7 @@ def django_boolean_icon(field_val, alt_text=None, title=None): title = '' icon_url = static('feincms/img/icon-%s.gif' % BOOLEAN_MAPPING[field_val]) return mark_safe( - u'<img src="%s" alt="%s" %s/>' % (icon_url, alt_text, title)) + '<img src="%s" alt="%s" %s/>' % (icon_url, alt_text, title)) def _build_tree_structure(queryset): @@ -105,7 +105,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): (useful for "disabled and you can't change it" situations). """ if text: - text = u' (%s)' % text + text = ' (%s)' % text if override is not None: a = [django_boolean_icon(override, text), text] @@ -121,7 +121,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): a.insert(0, '<div id="wrap_%s_%d">' % (attr, item.pk)) a.append('</div>') - return u''.join(a) + return ''.join(a) # ------------------------------------------------------------------------ @@ -287,7 +287,7 @@ def indented_short_title(self, item): if hasattr(item, 'short_title') and callable(item.short_title): r += escape(item.short_title()) else: - r += escape(u'%s' % item) + r += escape('%s' % item) # r += '</span>' return mark_safe(r) indented_short_title.short_description = _('title') @@ -490,7 +490,7 @@ def _move_node(self, request): try: tree_manager.move_node(cut_item, pasted_on, position) except InvalidMove as e: - self.message_user(request, u'%s' % e) + self.message_user(request, '%s' % e) return HttpResponse('FAIL') # Ensure that model save methods have been run (required to @@ -513,7 +513,7 @@ def _actions_column(self, instance): return [] def actions_column(self, instance): - return u' '.join(self._actions_column(instance)) + return ' '.join(self._actions_column(instance)) actions_column.allow_tags = True actions_column.short_description = _('actions') diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index a4ca3e415..ca7462fe1 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -336,7 +336,7 @@ def send_directly(self, request, response): or mimetype not in ('text/html', 'text/plain')) def render(self, **kwargs): - return getattr(self, 'rendered_result', u'') + return getattr(self, 'rendered_result', '') def finalize(self, request, response): headers = getattr(self, 'rendered_headers', None) diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index e36dc3182..be7f7a45f 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -45,7 +45,7 @@ def __init__(self, *args, **kwargs): if parent is not None: f = self.fields['comments_enabled'] r = f.help_text - r += u'<hr />' + r += '<hr />' comments_model = comments.get_model() for c in comments_model.objects.for_model( parent.parent).order_by('-submit_date'): @@ -82,7 +82,7 @@ def process(self, request, **kwargs): # works for now. #extra = request._feincms_extra_context.get('page_extra_path', ()) - #if len(extra) > 0 and extra[0] == u"post-comment": + #if len(extra) > 0 and extra[0] == "post-comment": r = post_comment(request, next=comment_page.get_absolute_url()) @@ -109,4 +109,4 @@ def process(self, request, **kwargs): ) def render(self, **kwargs): - return getattr(self, 'rendered_output', u'') + return getattr(self, 'rendered_output', '') diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index f5c68c2c4..35cb2f6b1 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -80,4 +80,4 @@ def process(self, request, **kwargs): context_instance=RequestContext(request)) def render(self, **kwargs): - return getattr(self, 'rendered_output', u'') + return getattr(self, 'rendered_output', '') diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index a2b1e2b72..d04080e5b 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -89,4 +89,4 @@ def render(self, **kwargs): return result - return u'' + return '' diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 3bd2dc848..b730f7ebe 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -102,7 +102,7 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, sort_tags Boolean, defaults to False. If set to True, a pre_save handler will be inserted to sort the tag field alphabetically. This is useful in case you want a canonical representation - for a tag collection, as when you're presenting a list of + for a tag collection, as when yo're presenting a list of tag combinations (e.g. in an admin filter list). select_field If True, show a multi select instead of the standard CharField for tag entry. diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 27330efe4..3336d4c25 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -50,10 +50,10 @@ def _fn(sender, **kwargs): ' %s:' % cls._meta.db_table)) for field in missing_columns: - print(u'%s:%s%s' % ( + print('%s:%s%s' % ( style.SQL_KEYWORD(field.column), ' ' * (25 - len(field.column)), - u'%s.%s' % ( + '%s.%s' % ( field.__class__.__module__, field.__class__.__name__), )) diff --git a/feincms/models.py b/feincms/models.py index baf0cd68c..a5263c671 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -176,7 +176,7 @@ def _fetch_content_type_count_helper(self, pk, regions=None): args.extend(regions * len(self.item._feincms_content_types)) tmpl.append('GROUP BY region') - tmpl = u' '.join(tmpl) + tmpl = ' '.join(tmpl) sql = ' UNION '.join([ tmpl % (idx, cls._meta.db_table, pk) @@ -457,8 +457,8 @@ class Meta: def __str__(self): return ( - u'%s<pk=%s, parent=%s<pk=%s, %s>, region=%s,' - u' ordering=%d>') % ( + '%s<pk=%s, parent=%s<pk=%s, %s>, region=%s,' + ' ordering=%d>') % ( self.__class__.__name__, self.pk, self.parent.__class__.__name__, @@ -508,7 +508,7 @@ def fe_identifier(self): content.) """ - return u'%s-%s-%s-%s-%s' % ( + return '%s-%s-%s-%s-%s' % ( cls._meta.app_label, cls._meta.module_name, self.__class__.__name__.lower(), @@ -691,7 +691,7 @@ class Meta(feincms_content_base.Meta): } new_type = type( - class_name, + str(class_name), (model, feincms_content_base,), attrs, ) diff --git a/feincms/module/blog/extensions/translations.py b/feincms/module/blog/extensions/translations.py index e4d8c9bf0..a63a03787 100644 --- a/feincms/module/blog/extensions/translations.py +++ b/feincms/module/blog/extensions/translations.py @@ -55,8 +55,8 @@ def available_translations(self): def available_translations_admin(self): translations = self.available_translations() - return u', '.join( - u'<a href="%s/">%s</a>' % ( + return ', '.join( + '<a href="%s/">%s</a>' % ( page.id, page.language.upper() ) for page in translations diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index d8ef8eb81..c6bb92791 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -120,7 +120,7 @@ def granular_save(obj, *args, **kwargs): def handle_modeladmin(self, modeladmin): def datepublisher_admin(self, obj): - return u'%s – %s' % ( + return '%s – %s' % ( format_date(obj.publication_date), format_date(obj.publication_end_date, '∞'), ) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 2a37f0d78..10065b685 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -81,7 +81,7 @@ def translation_set_language(request, select_language): # POST requests) response = HttpResponseRedirect(request.get_full_path()) response.set_cookie( - django_settings.LANGUAGE_COOKIE_NAME, select_language) + str(django_settings.LANGUAGE_COOKIE_NAME), select_language) return response @@ -235,12 +235,12 @@ def available_translations_admin(self, page): continue if key in translations: - links.append(u'<a href="%s/" title="%s">%s</a>' % ( + links.append('<a href="%s/" title="%s">%s</a>' % ( translations[key], _('Edit translation'), key.upper())) else: links.append( - u'<a style="color:#baa" href="add/?translation_of=' - u'%s&language=%s" title="%s">%s</a>' % ( + '<a style="color:#baa" href="add/?translation_of=' + '%s&language=%s" title="%s">%s</a>' % ( page.id, key, _('Create translation'), @@ -248,7 +248,7 @@ def available_translations_admin(self, page): ) ) - return u' | '.join(links) + return ' | '.join(links) available_translations_admin.allow_tags = True available_translations_admin.short_description = _('translations') diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 85e44dacf..f933f0dbb 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -31,16 +31,16 @@ def label_for_value(self, value): try: obj = self.rel.to._default_manager.using(self.db).get( **{key: value}) - label = [u' <strong>%s</strong>' % escape( + label = [' <strong>%s</strong>' % escape( shorten_string(six.text_type(obj)))] image = admin_thumbnail(obj) if image: label.append( - u'<br /><img src="%s" alt="" style="margin:1em 0 0 10em"' - u'/>' % image) + '<br /><img src="%s" alt="" style="margin:1em 0 0 10em"' + '/>' % image) - return u''.join(label) + return ''.join(label) except (ValueError, self.rel.to.DoesNotExist): return '' @@ -83,9 +83,9 @@ def render(self, name, value, attrs=None): image = admin_thumbnail(value.instance) if image: r = mark_safe(( - u'<img src="%s" alt="" style="float: left; padding-right:' - u'8px; border-right: 1px solid #ccc; margin-right: 8px"' - u'>' % image) + r) + '<img src="%s" alt="" style="float: left; padding-right:' + '8px; border-right: 1px solid #ccc; margin-right: 8px"' + '>' % image) + r) return r diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 82cb63608..4a43c198d 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -146,7 +146,7 @@ def changelist_view(self, request, extra_context=None): def admin_thumbnail(self, obj): image = admin_thumbnail(obj) if image: - return mark_safe(u""" + return mark_safe(""" <a href="%(url)s" target="_blank"> <img src="%(image)s" alt="" /> </a>""" % { @@ -196,9 +196,9 @@ def file_info(self, obj): JS, like for example a TinyMCE connector shim. """ return ( - u'<input type="hidden" class="medialibrary_file_path"' - u' name="_media_path_%d" value="%s" id="_refkey_%d" />' - u' %s <br />%s, %s' + '<input type="hidden" class="medialibrary_file_path"' + ' name="_media_path_%d" value="%s" id="_refkey_%d" />' + ' %s <br />%s, %s' ) % ( obj.id, obj.file.name, diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index fa766b834..c4f19a766 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -59,7 +59,7 @@ class Meta: def __str__(self): if self.parent_id: - return u'%s - %s' % (self.parent.title, self.title) + return '%s - %s' % (self.parent.title, self.title) return self.title @@ -152,7 +152,7 @@ def __str__(self): pass if trans: - trans = u'%s' % trans + trans = '%s' % trans if trans.strip(): return trans return os.path.basename(self.file.name) @@ -163,15 +163,15 @@ def get_absolute_url(self): def determine_file_type(self, name): """ >>> t = MediaFileBase() - >>> t.determine_file_type('foobar.jpg') + >>> str(t.determine_file_type('foobar.jpg')) 'image' - >>> t.determine_file_type('foobar.PDF') + >>> str(t.determine_file_type('foobar.PDF')) 'pdf' - >>> t.determine_file_type('foobar.jpg.pdf') + >>> str(t.determine_file_type('foobar.jpg.pdf')) 'pdf' - >>> t.determine_file_type('foobar.jgp') + >>> str(t.determine_file_type('foobar.jgp')) 'other' - >>> t.determine_file_type('foobar-jpg') + >>> str(t.determine_file_type('foobar-jpg')) 'other' """ for type_key, type_name, type_test in self.filetypes: diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index 5ce3f038f..e16ec9bf9 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -54,7 +54,7 @@ def content_title(self): @monkeypatch_property(self.model) def content_subtitle(self): - return u'\n'.join(self._content_title.splitlines()[1:]) + return '\n'.join(self._content_title.splitlines()[1:]) def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Titles'), { diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 81046771e..f15d083e9 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -31,13 +31,13 @@ def label_for_value(self, value): model = get_model(matches['app_label'], matches['module_name']) try: instance = model._default_manager.get(pk=int(matches['pk'])) - return u' <strong>%s (%s)</strong>' % ( + return ' <strong>%s (%s)</strong>' % ( instance, instance.get_absolute_url()) except model.DoesNotExist: pass - return u'' + return '' # ------------------------------------------------------------------------ @@ -134,7 +134,7 @@ def __init__(self, *args, **kwargs): if template.preview_image: choices.append(( template.key, - mark_safe(u'<img src="%s" alt="%s" /> %s' % ( + mark_safe('<img src="%s" alt="%s" /> %s' % ( template.preview_image, template.key, template.title, diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index ace81d8fa..80607d575 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -102,9 +102,9 @@ def _actions_column(self, page): if not page.template.enforce_leaf: actions.insert( 0, - u'<a href="add/?parent=%s" title="%s">' - u'<img src="%s" alt="%s" />' - u'</a>' % ( + '<a href="add/?parent=%s" title="%s">' + '<img src="%s" alt="%s" />' + '</a>' % ( page.pk, _('Add child page'), static('feincms/img/icon_addlink.gif'), @@ -113,9 +113,9 @@ def _actions_column(self, page): ) actions.insert( 0, - u'<a href="%s" title="%s">' - u'<img src="%s" alt="%s" />' - u'</a>' % ( + '<a href="%s" title="%s">' + '<img src="%s" alt="%s" />' + '</a>' % ( preview_url, _('View on site'), static('feincms/img/selector-search.gif'), diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 9f77fbb78..c23bf5bfe 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -56,7 +56,7 @@ def page_for_path(self, path, raise404=False): try: page = self.active().get( - _cached_url=u'/%s/' % stripped if stripped else '/') + _cached_url='/%s/' % stripped if stripped else '/') if not page.are_ancestors_active(): raise self.model.DoesNotExist('Parents are inactive.') @@ -258,9 +258,9 @@ def save(self, *args, **kwargs): if self.override_url: self._cached_url = self.override_url elif self.is_root_node(): - self._cached_url = u'/%s/' % self.slug + self._cached_url = '/%s/' % self.slug else: - self._cached_url = u'%s%s/' % (self.parent._cached_url, self.slug) + self._cached_url = '%s%s/' % (self.parent._cached_url, self.slug) cached_page_urls[self.id] = self._cached_url super(BasePage, self).save(*args, **kwargs) @@ -283,7 +283,7 @@ def save(self, *args, **kwargs): page._cached_url = page.override_url else: # cannot be root node by definition - page._cached_url = u'%s%s/' % ( + page._cached_url = '%s%s/' % ( cached_page_urls[page.parent_id], page.slug) @@ -295,8 +295,8 @@ def delete(self, *args, **kwargs): if not settings.FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED: if self.template.singleton: raise PermissionDenied(_( - u'This %(page_class)s uses a singleton template, and ' - u'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False' % { + 'This %(page_class)s uses a singleton template, and ' + 'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False' % { 'page_class': self._meta.verbose_name})) super(BasePage, self).delete(*args, **kwargs) self.invalidate_cache() @@ -371,7 +371,7 @@ def get_redirect_to_target(self, request): """ if not self.redirect_to: - return u'' + return '' # It might be an identifier for a different object match = REDIRECT_TO_RE.match(self.redirect_to) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 104d4a97a..1a51565e0 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -58,9 +58,9 @@ def frontendediting_request_processor(page, request): enable_fe = False if enable_fe: - response.set_cookie('frontend_editing', enable_fe) + response.set_cookie(str('frontend_editing'), enable_fe) else: - response.delete_cookie('frontend_editing') + response.delete_cookie(str('frontend_editing')) # Redirect to cleanup URLs return response diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 0997dd076..37c1ab8ce 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -35,7 +35,7 @@ def _get_page_model(): # TODO: Belongs in some utility module def format_exception(e): top = traceback.extract_tb(sys.exc_info()[2])[-1] - return u"'%s' in %s line %d" % (e, top[0], top[1]) + return "'%s' in %s line %d" % (e, top[0], top[1]) # ------------------------------------------------------------------------ @@ -214,7 +214,7 @@ def what(self, page, args): # Preserve the trailing path when switching languages if extra_path # exists (this is mostly the case when we are working inside an # ApplicationContent-managed page subtree) - trailing_path = u'' + trailing_path = '' request = args.get('request', None) if request: # Trailing path without first slash diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index a4c6d435a..fb7ce6a4c 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -35,7 +35,7 @@ def feincms_render_region_appcontent(page, region, request): {% feincms_render_region_appcontent feincms_page "main" request %} {% endif %} """ - return u''.join( + return ''.join( _render_content(content, request=request) for content in page.content.all_of_type(ApplicationContent) if content.region == region) @@ -68,7 +68,7 @@ def render(self, context): if self.asvar: context[self.asvar] = url - return u'' + return '' else: return url diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 23ce93746..666db0bc0 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -48,7 +48,7 @@ def feincms_render_region(context, feincms_object, region, request=None): """ {% feincms_render_region feincms_page "main" request %} """ - return u''.join( + return ''.join( _render_content(content, request=request, context=context) for content in getattr(feincms_object.content, region)) @@ -74,7 +74,7 @@ def feincms_frontend_editing(cms_obj, request): }) return render_to_string('admin/feincms/fe_tools.html', context) - return u'' + return '' @register.inclusion_tag('admin/feincms/content_type_selection_widget.html', diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index ddf2d7992..2682f6af3 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -47,7 +47,7 @@ def url(self): def __str__(self): match = self.THUMBNAIL_SIZE_RE.match(self.size) if not (self.filename and match): - return u'' + return '' matches = match.groupdict() @@ -69,7 +69,7 @@ def __str__(self): except ValueError: basename, format = filename, 'jpg' - miniature = u''.join([ + miniature = ''.join([ settings.FEINCMS_THUMBNAIL_DIR, basename, self.MARKER, @@ -90,7 +90,7 @@ def __str__(self): generate = False except (OSError, IOError): # Someone might have delete the file - return u'' + return '' if generate: return self.generate( diff --git a/feincms/templatetags/fragment_tags.py b/feincms/templatetags/fragment_tags.py index 7cf8dabaf..5c5e7098b 100644 --- a/feincms/templatetags/fragment_tags.py +++ b/feincms/templatetags/fragment_tags.py @@ -21,7 +21,7 @@ def render(self, context): if not hasattr(request, '_feincms_fragments'): request._feincms_fragments = {} - old = request._feincms_fragments.get(identifier, u'') + old = request._feincms_fragments.get(identifier, '') if self.mode == 'prepend': request._feincms_fragments[identifier] = rendered + old @@ -30,7 +30,7 @@ def render(self, context): else: # append request._feincms_fragments[identifier] = old + rendered - return u'' + return '' @register.tag @@ -69,11 +69,11 @@ def render(self, context): try: value = request._feincms_fragments[fragment] except (AttributeError, KeyError): - value = u'' + value = '' if self.as_var: context[self.as_var] = value - return u'' + return '' return value diff --git a/feincms/translations.py b/feincms/translations.py index a540471e8..82c761bea 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -55,9 +55,9 @@ def short_language_code(code=None): Extract the short language code from its argument (or return the default language code). - >>> short_language_code('de') + >>> str(short_language_code('de')) 'de' - >>> short_language_code('de-at') + >>> str(short_language_code('de-at')) 'de' >>> short_language_code() == short_language_code(settings.LANGUAGE_CODE) True @@ -253,7 +253,7 @@ def __str__(self): return self.__class__.__name__ if translation: - return u'%s' % translation + return '%s' % translation return self.__class__.__name__ diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 236bbe626..27a0c1bd6 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -64,7 +64,7 @@ def copy_model_instance(obj, exclude=None): # ------------------------------------------------------------------------ -def shorten_string(str, max_length=50, ellipsis=u' … '): +def shorten_string(str, max_length=50, ellipsis=' … '): """ Shorten a string for display, truncate it intelligently when too long. Try to cut it in 2/3 + ellipsis + 1/3 of the original title. Also try to @@ -116,26 +116,26 @@ def get_singleton(template_key, cls=None, raise_exception=True): try: model = get_model(*cls.split('.')) if not model: - raise ImproperlyConfigured(u'Cannot load model "%s"' % cls) + raise ImproperlyConfigured('Cannot load model "%s"' % cls) try: assert model._feincms_templates[template_key].singleton except AttributeError as e: raise ImproperlyConfigured( - u'%r does not seem to be a valid FeinCMS base class (%r)' % ( + '%r does not seem to be a valid FeinCMS base class (%r)' % ( model, e, ) ) except KeyError: raise ImproperlyConfigured( - u'%r is not a registered template for %r!' % ( + '%r is not a registered template for %r!' % ( template_key, model, ) ) except AssertionError: raise ImproperlyConfigured( - u'%r is not a *singleton* template for %r!' % ( + '%r is not a *singleton* template for %r!' % ( template_key, model, ) diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index 7df7d9148..2f9e7e108 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -2,6 +2,8 @@ This is a dummy module used to test the ApplicationContent """ +from __future__ import absolute_import, unicode_literals + from django.conf.urls import patterns, url from django.http import HttpResponse, HttpResponseRedirect from django.template.loader import render_to_string @@ -14,7 +16,7 @@ def module_root(request): def args_test(request, kwarg1, kwarg2): - return HttpResponse(u'%s-%s' % (kwarg1, kwarg2)) + return HttpResponse('%s-%s' % (kwarg1, kwarg2)) def full_reverse_test(request): diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 9b3c45ab7..23ef36d77 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from django import forms from django.db import models from django.utils.encoding import python_2_unicode_compatible @@ -131,6 +133,6 @@ def __str__(self): # add m2m field to entry so it shows up in entry admin Entry.add_to_class( - 'categories', + str('categories'), models.ManyToManyField(Category, blank=True, null=True)) EntryAdmin.list_filter += ('categories',) diff --git a/tests/testapp/navigation_extensions.py b/tests/testapp/navigation_extensions.py index 749aa0762..bbd691839 100644 --- a/tests/testapp/navigation_extensions.py +++ b/tests/testapp/navigation_extensions.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + from feincms.module.page.extensions.navigation import ( NavigationExtension, PagePretender) diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 57ba1fb02..cea66cb3a 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + import os SITE_ID = 1 diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index e41ad5741..75023a733 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals import os diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 8e377c8d8..60ad3c05f 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -1,6 +1,6 @@ # coding: utf-8 -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals from django.contrib.sites.models import Site from django.template.defaultfilters import slugify @@ -24,7 +24,7 @@ def setUp(self): # create a bunch of pages en = self.create_default_page_set(language='en') - de = self.create_default_page_set(language='de', title=u'Testseite') + de = self.create_default_page_set(language='de', title='Testseite') de.translation_of = en de.save() de.parent.translation_of = en.parent diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 0af78ac4a..91d3c77f7 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -2,7 +2,7 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals from datetime import datetime, timedelta import os @@ -170,7 +170,7 @@ def test_02_add_page(self): slug='test-page'), '/admin/page/page/') self.assertEqual(Page.objects.count(), 1) - self.assertContains(self.client.get('/admin/page/page/'), u'…') + self.assertContains(self.client.get('/admin/page/page/'), '…') def test_03_item_editor(self): self.login() @@ -410,8 +410,8 @@ def test_09_pagecontent(self): page2.content.main[0].__class__.__name__, 'RawContent') self.assertEqual( force_text(page2.content.main[0]), - u'RawContent<pk=1, parent=Page<pk=1, Test page>, region=main,' - u' ordering=0>') + 'RawContent<pk=1, parent=Page<pk=1, Test page>, region=main,' + ' ordering=0>') self.assertEqual(len(page2.content.main), 1) self.assertEqual(len(page2.content.sidebar), 0) @@ -596,7 +596,7 @@ def test_13_inheritance_and_ct_tracker(self): 0, lambda: page2.content.sidebar[0].render()) self.assertEqual( - u''.join(c.render() for c in page2.content.main), + ''.join(c.render() for c in page2.content.main), 'Something elseWhatever') self.assertEqual(page2.content.sidebar[0].render(), 'Something') @@ -662,7 +662,7 @@ def test_15_frontend_editing(self): }).status_code, 200) self.assertEqual(page.content.main[0].render(), 'blablabla') - self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), u'') + self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), '') request = Empty() request.COOKIES = {'frontend_editing': "True"} @@ -1028,7 +1028,7 @@ def test_17_feincms_nav(self): ).strip(), self.assertEqual( data, - (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), + ('1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") p.active = False @@ -1038,7 +1038,7 @@ def test_17_feincms_nav(self): ).strip(), self.assertEqual( data, - (u'1,2,3,4,6,7,8,10,11,12,13,14',), + ('1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") # Same test with feincms_nav @@ -1052,7 +1052,7 @@ def test_17_feincms_nav(self): ).strip(), self.assertEqual( data, - (u'1,2,3,4,6,7,8,10,11,12,13,14',), + ('1,2,3,4,6,7,8,10,11,12,13,14',), "Navigation after disabling intermediate page") p.active = True @@ -1063,7 +1063,7 @@ def test_17_feincms_nav(self): ).strip(), self.assertEqual( data, - (u'1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), + ('1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), "Original navigation") def test_18_default_render_method(self): @@ -1077,7 +1077,7 @@ class Meta: abstract = True def render_main(self): - return u'Hello' + return 'Hello' # do not register this model in the internal FeinCMS bookkeeping # structures diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 9c374cc8a..3fdf06fe2 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -2,6 +2,8 @@ # coding=utf-8 # ------------------------------------------------------------------------ +from __future__ import absolute_import, unicode_literals + import doctest from django.contrib.auth.models import User @@ -72,21 +74,21 @@ def test_collect_dict_values(self): def test_shorten_string(self): string = shorten_string( - u"Der Wolf und die Grossmutter assen im Wald zu mittag", - 15, ellipsis=u"_") - self.assertEqual(string, u'Der Wolf und_ag') + "Der Wolf und die Grossmutter assen im Wald zu mittag", + 15, ellipsis="_") + self.assertEqual(string, 'Der Wolf und_ag') self.assertEqual(len(string), 15) string = shorten_string( - u"Haenschen-Klein, ging allein, in den tiefen Wald hinein", + "Haenschen-Klein, ging allein, in den tiefen Wald hinein", 15) - self.assertEqual(string, u'Haenschen \u2026 ein') + self.assertEqual(string, 'Haenschen \u2026 ein') self.assertEqual(len(string), 15) string = shorten_string( - u'Badgerbadgerbadgerbadgerbadger', - 10, ellipsis=u'-') - self.assertEqual(string, u'Badger-ger') + 'Badgerbadgerbadgerbadgerbadger', + 10, ellipsis='-') + self.assertEqual(string, 'Badger-ger') self.assertEqual(len(string), 10) diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index fb87587cd..7610a56ea 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, unicode_literals + import os from django.conf.urls import patterns, include, url diff --git a/tests/tox-update-venvs.sh b/tests/tox-update-venvs.sh index 103984fb9..5832dbfec 100755 --- a/tests/tox-update-venvs.sh +++ b/tests/tox-update-venvs.sh @@ -4,6 +4,10 @@ cd .tox/py27-1.7.X bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev ) +( + cd .tox/py32-1.7.X + bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev +) ( cd .tox/py33-1.7.X bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev From cce4a9534ea32282de80e6229834af07bf2ec70f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 30 Dec 2013 21:07:17 +0100 Subject: [PATCH 0912/1590] Django 1.7's get_model raises instead of returning None --- feincms/models.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index a5263c671..9286047cc 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -652,8 +652,14 @@ def create_content_type(cls, model, regions=None, class_name=None, # Next name clash test. Happens when the same content type is # created for two Base subclasses living in the same Django # application (github issues #73 and #150) - other_model = get_model(cls._meta.app_label, class_name) - if other_model: + try: + other_model = get_model(cls._meta.app_label, class_name) + if other_model is None: + # Django 1.6 and earlier + raise LookupError + except LookupError: + pass + else: warnings.warn( 'It seems that the content type %s exists twice in %s.' ' Use the class_name argument to create_content_type to' From 73afc3dc26016a98311a8eeebe389ed4b77170e0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 30 Dec 2013 21:25:27 +0100 Subject: [PATCH 0913/1590] Hack for running tests with Django 1.7, add a note to a failing test --- feincms/__init__.py | 9 +++++++-- tests/testapp/tests/test_cms.py | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index d45999052..869a5897d 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -79,6 +79,11 @@ def ensure_completely_loaded(force=False): if hasattr(loading, 'cache'): loading.cache._get_models_cache.clear() - if loading.app_cache_ready(): - COMPLETELY_LOADED = True + if hasattr(loading.app_cache_ready, '__call__'): + if loading.app_cache_ready(): + COMPLETELY_LOADED = True + else: + # TODO Django 1.7 offers us better ways of handling this, maybe. + if loading.app_cache_ready: + COMPLETELY_LOADED = True return True diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 75023a733..1cc564ca7 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -154,6 +154,11 @@ def test_09_related_objects_cache(self): objects added after the last content type time missed the boat. Now we delete the cache so hopefully _fill_*_cache* won't be called until all related models have been defined. + + TODO that's a dumb test, we should try being less dynamic instead of + supporting all types of ad-hoc definitions of models etc. + + It also fails on Django 1.7 since the introduction of django.apps """ class Attachment(models.Model): base = models.ForeignKey( From 169bc55d88700cd496d99c24533265fc9a703937 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 30 Dec 2013 21:26:49 +0100 Subject: [PATCH 0914/1590] Add Python 3.2 to .travis.yml --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 19723fc4b..29456b4e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: python python: - - "2.7" - "2.6" + - "2.7" + - "3.2" - "3.3" env: - DJANGO_VERSION=1.4.10 @@ -9,6 +10,8 @@ env: - DJANGO_VERSION=1.6.0 matrix: exclude: + - python: "3.2" + env: DJANGO_VERSION=1.4.10 - python: "3.3" env: DJANGO_VERSION=1.4.10 # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors From 245cfad12f776f84f16095b41095dc0fde7c68ea Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 30 Dec 2013 21:27:58 +0100 Subject: [PATCH 0915/1590] Add a trove classifier for Python 3.2 [ci skip] --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b7bef126f..22c807b00 100755 --- a/setup.py +++ b/setup.py @@ -52,6 +52,7 @@ def read(filename): 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development', From bd9f017bd5021d4bf92cac8442047473aca85248 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 4 Jan 2014 11:43:04 +0100 Subject: [PATCH 0916/1590] Also run flake8 on travis CI --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 29456b4e1..ea5c5150d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ matrix: env: DJANGO_VERSION=1.4.10 # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - - pip install -q Django==$DJANGO_VERSION django-mptt Pillow feedparser --use-mirrors + - pip install -q Django==$DJANGO_VERSION django-mptt Pillow feedparser flake8 --use-mirrors - python setup.py -q install # command to run tests, e.g. python setup.py test -script: "cd tests && ./manage.py test testapp" +script: "cd tests && ./manage.py test testapp && flake8 ." From 7a319f78c5a5cd0c60e6141d1221f3c7a0d4a7f0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 6 Jan 2014 11:19:04 +0100 Subject: [PATCH 0917/1590] FeinCMS v1.9.2 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 869a5897d..a22caad0e 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 9, 1) +VERSION = (1, 9, 2) __version__ = '.'.join(map(str, VERSION)) From 38b2108b1b8153dc0898985226cb317c24bb333b Mon Sep 17 00:00:00 2001 From: Artur Barseghyan <artur.barseghyan@gmail.com> Date: Mon, 6 Jan 2014 16:00:13 +0100 Subject: [PATCH 0918/1590] Update page.rst Absolute path to the extensions. --- docs/page.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/page.rst b/docs/page.rst index 06a7cdb83..d57566a9e 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -39,7 +39,10 @@ by adding the following lines somewhere into your project, for example in a from feincms.content.richtext.models import RichTextContent from feincms.content.medialibrary.models import MediaFileContent - Page.register_extensions('datepublisher', 'translations') # Example set of extensions + Page.register_extensions( + 'feincms.module.extensions.datepublisher', + 'feincms.module.extensions.translations' + ) # Example set of extensions Page.register_templates({ 'title': _('Standard template'), From ee0dd599835c2955ac62ca3ce5fbf1a2a6de6a15 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 3 Feb 2014 13:32:11 +0100 Subject: [PATCH 0919/1590] Fix #511: UnicodeDecodeError if subpage not found --- feincms/content/application/models.py | 2 +- feincms/module/mixins.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index ca7462fe1..867a8cf4d 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -269,7 +269,7 @@ def process(self, request, **kw): try: fn, args, kwargs = resolve(path, urlconf_path) except (ValueError, Resolver404): - raise Resolver404('Not found (resolving %r in %r failed)' % ( + raise Resolver404(str('Not found (resolving %r in %r failed)') % ( path, urlconf_path)) # Variables from the ApplicationContent parameters are added to request diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index b9d2d8303..792576141 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -195,7 +195,7 @@ def process_content_types(self): # XXX Already inside application content. I'm not sure # whether this fix is really correct... and not extra_context.get('app_config')): - raise Http404('Not found (extra_path %r on %r)' % ( + raise Http404(str('Not found (extra_path %r on %r)') % ( extra_context.get('extra_path', '/'), self.object, )) From 73e692ba0e2e5570b3ca3b7c9fae87fb23489b8e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 4 Feb 2014 09:13:02 +0100 Subject: [PATCH 0920/1590] Fix a typo in a (private) method name --- feincms/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 9286047cc..b3b1eaaaa 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -194,7 +194,7 @@ def _fetch_content_type_count_helper(self, pk, regions=None): return _c - def _popuplate_content_type_caches(self, types): + def _populate_content_type_caches(self, types): """ Populate internal caches for all content types passed """ @@ -230,7 +230,7 @@ def _fetch_regions(self): """ if 'regions' not in self._cache: - self._popuplate_content_type_caches( + self._populate_content_type_caches( self.item._feincms_content_types) contents = {} for cls, content_list in self._cache['cts'].items(): @@ -260,7 +260,7 @@ def all_of_type(self, type_or_tuple): content_list = [] if not hasattr(type_or_tuple, '__iter__'): type_or_tuple = (type_or_tuple,) - self._popuplate_content_type_caches(type_or_tuple) + self._populate_content_type_caches(type_or_tuple) for type, contents in self._cache['cts'].items(): if any(issubclass(type, t) for t in type_or_tuple): From 6726468d1ff85e7b6f6acc88ad993518cc998aad Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 4 Feb 2014 09:14:33 +0100 Subject: [PATCH 0921/1590] FeinCMS v1.9.3 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index a22caad0e..823e59932 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 9, 2) +VERSION = (1, 9, 3) __version__ = '.'.join(map(str, VERSION)) From 7916cac924f77367c5af9da4d18ad8a5609eceb4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 4 Feb 2014 09:16:53 +0100 Subject: [PATCH 0922/1590] Development branch --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 823e59932..a472b6c55 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 9, 3) +VERSION = (1, 10, 0, 'pre') __version__ = '.'.join(map(str, VERSION)) From 3bd189e1d6972edde8567ef3393720d1cefdeec0 Mon Sep 17 00:00:00 2001 From: Stefan Reinhard <sr@feinheit.ch> Date: Tue, 4 Feb 2014 15:20:22 +0100 Subject: [PATCH 0923/1590] Populate values for ApplicationContent admin_fields from parameters --- feincms/content/application/models.py | 2 ++ tests/testapp/models.py | 1 + tests/testapp/tests/test_page.py | 11 +++++++++++ 3 files changed, 14 insertions(+) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 867a8cf4d..919eb1bbf 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -212,6 +212,8 @@ def __init__(self, *args, **kwargs): for k, v in self.custom_fields.items(): self.fields[k] = v + if k in self.instance.parameters: + self.fields[k].initial = self.instance.parameters[k] def save(self, commit=True, *args, **kwargs): # Django ModelForms return the model instance from save. We'll diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 23ef36d77..668202fc1 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -53,6 +53,7 @@ def get_admin_fields(form, *args, **kwargs): 'Exclude everything other than the application\'s content' ' when rendering subpages.'), ), + 'custom_field': forms.CharField(), } diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 91d3c77f7..7f3431df8 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1416,6 +1416,17 @@ def test_25_applicationcontent(self): self.assertContains( self.client.get('/admin/page/page/%d/' % page.id), 'exclusive_subpages') + self.assertContains( + self.client.get('/admin/page/page/%d/' % page.id), + 'custom_field' + ) + + # Check if admin_fields get populated correctly + app_ct = page.applicationcontent_set.all()[0] + app_ct.parameters = '{"custom_field":"val42", "exclusive_subpages": false}' + app_ct.save() + r = self.client.get('/admin/page/page/%d/' % page.id) + self.assertContains(r, 'val42') def test_26_page_form_initial(self): self.create_default_page_set() From 681d279ca291c8edfb82b02c3fd91c77f693d09a Mon Sep 17 00:00:00 2001 From: Stefan Reinhard <sr@feinheit.ch> Date: Tue, 4 Feb 2014 16:25:49 +0100 Subject: [PATCH 0924/1590] flake8 clean --- feincms/content/application/models.py | 3 +-- tests/testapp/tests/test_page.py | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 919eb1bbf..867295e65 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -211,9 +211,8 @@ def __init__(self, *args, **kwargs): get_fields(self, *args, **kwargs)) for k, v in self.custom_fields.items(): + v.initial = self.instance.parameters.get(k) self.fields[k] = v - if k in self.instance.parameters: - self.fields[k].initial = self.instance.parameters[k] def save(self, commit=True, *args, **kwargs): # Django ModelForms return the model instance from save. We'll diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 7f3431df8..d18fe3228 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1423,7 +1423,8 @@ def test_25_applicationcontent(self): # Check if admin_fields get populated correctly app_ct = page.applicationcontent_set.all()[0] - app_ct.parameters = '{"custom_field":"val42", "exclusive_subpages": false}' + app_ct.parameters = \ + '{"custom_field":"val42", "exclusive_subpages": false}' app_ct.save() r = self.client.get('/admin/page/page/%d/' % page.id) self.assertContains(r, 'val42') From 6f946661120386d8a5f42e56752f802d65fa626c Mon Sep 17 00:00:00 2001 From: Stefan Reinhard <sr@feinheit.ch> Date: Tue, 4 Feb 2014 15:20:22 +0100 Subject: [PATCH 0925/1590] Populate values for ApplicationContent admin_fields from parameters --- feincms/content/application/models.py | 2 ++ feincms/tests/test_page.py | 11 +++++++++++ tests/testapp/models.py | 5 +++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index f0cdcab86..156ecaa25 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -281,6 +281,8 @@ def __init__(self, *args, **kwargs): for k, v in self.custom_fields.items(): self.fields[k] = v + if k in self.instance.parameters: + self.fields[k].initial = self.instance.parameters[k] def save(self, commit=True, *args, **kwargs): # Django ModelForms return the model instance from save. We'll diff --git a/feincms/tests/test_page.py b/feincms/tests/test_page.py index 1aa7e80be..34c2e38fb 100644 --- a/feincms/tests/test_page.py +++ b/feincms/tests/test_page.py @@ -1179,6 +1179,17 @@ def test_25_applicationcontent(self): # Ensure ApplicationContent's admin_fields support works properly self.assertContains(self.client.get('/admin/page/page/%d/' % page.id), 'exclusive_subpages') + self.assertContains( + self.client.get('/admin/page/page/%d/' % page.id), + 'custom_field' + ) + + # Check if admin_fields get populated correctly + app_ct = page.applicationcontent_set.all()[0] + app_ct.parameters = '{"custom_field":"val42", "exclusive_subpages": false}' + app_ct.save() + r = self.client.get('/admin/page/page/%d/' % page.id) + self.assertContains(r, 'val42') def test_26_page_form_initial(self): self.create_default_page_set() diff --git a/tests/testapp/models.py b/tests/testapp/models.py index b6fa6d39f..2a368f317 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -38,8 +38,9 @@ def get_admin_fields(form, *args, **kwargs): label=capfirst(_('exclusive subpages')), required=False, initial=form.instance.parameters.get('exclusive_subpages', False), - help_text=_('Exclude everything other than the application\'s content when rendering subpages.'), - ), + help_text=_('Exclude everything other when rendering subpages.'), + ), + 'custom_field': forms.CharField(), } Page.create_content_type(ApplicationContent, APPLICATIONS=( From ca4aa5226e91e9e18ad294ed0346a060e0fe3c13 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 7 Feb 2014 11:00:15 +0100 Subject: [PATCH 0926/1590] Add a blurp about adding other rich text libraries to the docs, curtesy of Matthia's answer to a ticket. --- docs/contenttypes.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 89c27bd04..4c6e08551 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -431,6 +431,25 @@ Additional arguments for :func:`~feincms.models.Base.create_content_type`: which are not explicitly whitelisted. The default is ``False``. +Other rich text libraries +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Other rich text widgets can be wired up for the RichTextContent. +You would have to write two functions: One which is called when +rich text editing functionality is added ("richify"), and another +one which is called when functionality is removed ("poorify"). +The second is necessary because rich text editors do not like +being dragged; when dragging a rich text content type, it is first +poorified and then richified again as soon as the content type has +been dropped into its final position. + +To perform those operations + * Add a function adding the new rich text editor to + ``contentblock_init_handlers`` and to ``contentblock_move_handlers.richify`` + * Add a function removing the rich text editor to + ``contentblock_move_handlers.poorify`` + + RSS feeds --------- .. module:: feincms.content.rss.models From a6ee8b89f09ea284ddc2cf5ee5512898ea90f622 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 7 Feb 2014 11:13:25 +0100 Subject: [PATCH 0927/1590] Update jquery to 1.11.0 --- feincms/static/feincms/jquery-1.11.0.min.js | 4 ++++ feincms/templates/admin/feincms/load-jquery.include | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 feincms/static/feincms/jquery-1.11.0.min.js diff --git a/feincms/static/feincms/jquery-1.11.0.min.js b/feincms/static/feincms/jquery-1.11.0.min.js new file mode 100644 index 000000000..73f33fb3a --- /dev/null +++ b/feincms/static/feincms/jquery-1.11.0.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f +}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},W=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a>",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=$.test(e)?this.mouseHooks:Z.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||z),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||z,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==db()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===db()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=z.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===L&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&(a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault())?bb:cb):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:cb,isPropagationStopped:cb,isImmediatePropagationStopped:cb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=bb,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=bb,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submitBubbles||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?b.form:void 0;c&&!n._data(c,"submitBubbles")&&(n.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),n._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.changeBubbles||(n.event.special.change={setup:function(){return Y.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),n.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),n.event.simulate("change",this,a,!0)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;Y.test(b.nodeName)&&!n._data(b,"changeBubbles")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a,!0)}),n._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!Y.test(this.nodeName)}}),l.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=cb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return n().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=cb),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});function eb(a){var b=fb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var fb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gb=/ jQuery\d+="(?:null|\d+)"/g,hb=new RegExp("<(?:"+fb+")[\\s/>]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/<tbody/i,mb=/<|&#?\w+;/,nb=/<(?:script|style|link)/i,ob=/checked\s*(?:[^=]|=\s*.checked.)/i,pb=/^$|\/(?:java|ecma)script/i,qb=/^true\/(.*)/,rb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,sb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1></$2>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?"<table>"!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Db[0].contentWindow||Db[0].contentDocument).document,b.write(),b.close(),c=Fb(a,b),Db.detach()),Eb[a]=c),c}!function(){var a,b,c=z.createElement("div"),d="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";c.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],a.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(a.style.opacity),l.cssFloat=!!a.style.cssFloat,c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===c.style.backgroundClip,a=c=null,l.shrinkWrapBlocks=function(){var a,c,e,f;if(null==b){if(a=z.getElementsByTagName("body")[0],!a)return;f="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",c=z.createElement("div"),e=z.createElement("div"),a.appendChild(c).appendChild(e),b=!1,typeof e.style.zoom!==L&&(e.style.cssText=d+";width:1px;padding:1px;zoom:1",e.innerHTML="<div></div>",e.firstChild.style.width="5px",b=3!==e.offsetWidth),a.removeChild(c),a=c=e=null}return b}}();var Hb=/^margin/,Ib=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Jb,Kb,Lb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Jb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),Ib.test(g)&&Hb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):z.documentElement.currentStyle&&(Jb=function(a){return a.currentStyle},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ib.test(g)&&!Lb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Mb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h=z.createElement("div"),i="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",j="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";h.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",b=h.getElementsByTagName("a")[0],b.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(b.style.opacity),l.cssFloat=!!b.style.cssFloat,h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,b=h=null,n.extend(l,{reliableHiddenOffsets:function(){if(null!=c)return c;var a,b,d,e=z.createElement("div"),f=z.getElementsByTagName("body")[0];if(f)return e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=z.createElement("div"),a.style.cssText=i,f.appendChild(a).appendChild(e),e.innerHTML="<table><tr><td></td><td>t</td></tr></table>",b=e.getElementsByTagName("td"),b[0].style.cssText="padding:0;margin:0;border:0;display:none",d=0===b[0].offsetHeight,b[0].style.display="",b[1].style.display="none",c=d&&0===b[0].offsetHeight,f.removeChild(a),e=f=null,c},boxSizing:function(){return null==d&&k(),d},boxSizingReliable:function(){return null==e&&k(),e},pixelPosition:function(){return null==f&&k(),f},reliableMarginRight:function(){var b,c,d,e;if(null==g&&a.getComputedStyle){if(b=z.getElementsByTagName("body")[0],!b)return;c=z.createElement("div"),d=z.createElement("div"),c.style.cssText=i,b.appendChild(c).appendChild(d),e=d.appendChild(z.createElement("div")),e.style.cssText=d.style.cssText=j,e.style.marginRight=e.style.width="0",d.style.width="1px",g=!parseFloat((a.getComputedStyle(e,null)||{}).marginRight),b.removeChild(c)}return g}});function k(){var b,c,h=z.getElementsByTagName("body")[0];h&&(b=z.createElement("div"),c=z.createElement("div"),b.style.cssText=i,h.appendChild(b).appendChild(c),c.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;display:block;padding:1px;border:1px;width:4px;margin-top:1%;top:1%",n.swap(h,null!=h.style.zoom?{zoom:1}:{},function(){d=4===c.offsetWidth}),e=!0,f=!1,g=!0,a.getComputedStyle&&(f="1%"!==(a.getComputedStyle(c,null)||{}).top,e="4px"===(a.getComputedStyle(c,null)||{width:"4px"}).width),h.removeChild(b),c=h=null)}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Nb=/alpha\([^)]*\)/i,Ob=/opacity\s*=\s*([^)]*)/,Pb=/^(none|table(?!-c[ea]).+)/,Qb=new RegExp("^("+T+")(.*)$","i"),Rb=new RegExp("^([+-])=("+T+")","i"),Sb={position:"absolute",visibility:"hidden",display:"block"},Tb={letterSpacing:0,fontWeight:400},Ub=["Webkit","O","Moz","ms"];function Vb(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ub.length;while(e--)if(b=Ub[e]+c,b in a)return b;return d}function Wb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=n._data(d,"olddisplay",Gb(d.nodeName)))):f[g]||(e=V(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Xb(a,b,c){var d=Qb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Yb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Zb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Jb(a),g=l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Kb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ib.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Yb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Kb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=Vb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Rb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]="",i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Vb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Kb(a,b,d)),"normal"===f&&b in Tb&&(f=Tb[b]),""===c||c?(e=parseFloat(f),c===!0||n.isNumeric(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&Pb.test(n.css(a,"display"))?n.swap(a,Sb,function(){return Zb(a,b,d)}):Zb(a,b,d):void 0},set:function(a,c,d){var e=d&&Jb(a);return Xb(a,c,d?Yb(a,b,d,l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Ob.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Nb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Nb.test(f)?f.replace(Nb,e):f+" "+e)}}),n.cssHooks.marginRight=Mb(l.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},Kb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Hb.test(a)||(n.cssHooks[a+b].set=Xb)}),n.fn.extend({css:function(a,b){return W(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Jb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b) +},a,b,arguments.length>1)},show:function(){return Wb(this,!0)},hide:function(){return Wb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function $b(a,b,c,d,e){return new $b.prototype.init(a,b,c,d,e)}n.Tween=$b,$b.prototype={constructor:$b,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=$b.propHooks[this.prop];return a&&a.get?a.get(this):$b.propHooks._default.get(this)},run:function(a){var b,c=$b.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):$b.propHooks._default.set(this),this}},$b.prototype.init.prototype=$b.prototype,$b.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},$b.propHooks.scrollTop=$b.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=$b.prototype.init,n.fx.step={};var _b,ac,bc=/^(?:toggle|show|hide)$/,cc=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),dc=/queueHooks$/,ec=[jc],fc={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=cc.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&cc.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function gc(){return setTimeout(function(){_b=void 0}),_b=n.now()}function hc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=U[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function ic(a,b,c){for(var d,e=(fc[b]||[]).concat(fc["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function jc(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&V(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k=Gb(a.nodeName),"none"===j&&(j=k),"inline"===j&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==k?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],bc.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}if(!n.isEmptyObject(o)){r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=ic(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function kc(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function lc(a,b,c){var d,e,f=0,g=ec.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=_b||gc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:_b||gc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(kc(k,j.opts.specialEasing);g>f;f++)if(d=ec[f].call(j,a,k,j.opts))return d;return n.map(k,ic,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(lc,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],fc[c]=fc[c]||[],fc[c].unshift(b)},prefilter:function(a,b){b?ec.unshift(a):ec.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=lc(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&dc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(hc(b,!0),a,d,e)}}),n.each({slideDown:hc("show"),slideUp:hc("hide"),slideToggle:hc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(_b=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),_b=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ac||(ac=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(ac),ac=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e=z.createElement("div");e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=e.getElementsByTagName("a")[0],c=z.createElement("select"),d=c.appendChild(z.createElement("option")),b=e.getElementsByTagName("input")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==e.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=d.selected,l.enctype=!!z.createElement("form").enctype,c.disabled=!0,l.optDisabled=!d.disabled,b=z.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value,a=b=c=d=e=null}();var mc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(mc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.text(a)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var nc,oc,pc=n.expr.attrHandle,qc=/^(?:checked|selected)$/i,rc=l.getSetAttribute,sc=l.input;n.fn.extend({attr:function(a,b){return W(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===L?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?oc:nc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(F);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?sc&&rc||!qc.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(rc?c:d)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),oc={set:function(a,b,c){return b===!1?n.removeAttr(a,c):sc&&rc||!qc.test(c)?a.setAttribute(!rc&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=pc[b]||n.find.attr;pc[b]=sc&&rc||!qc.test(b)?function(a,b,d){var e,f;return d||(f=pc[b],pc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,pc[b]=f),e}:function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),sc&&rc||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):nc&&nc.set(a,b,c)}}),rc||(nc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},pc.id=pc.name=pc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:nc.set},n.attrHooks.contenteditable={set:function(a,b,c){nc.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var tc=/^(?:input|select|textarea|button|object)$/i,uc=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return W(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):tc.test(a.nodeName)||uc.test(a.nodeName)&&a.href?0:-1}}}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var vc=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(F)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===L||"boolean"===c)&&(this.className&&n._data(this,"__className__",this.className),this.className=this.className||a===!1?"":n._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(vc," ").indexOf(b)>=0)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var wc=n.now(),xc=/\?/,yc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(yc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var zc,Ac,Bc=/#.*$/,Cc=/([?&])_=[^&]*/,Dc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ec=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Fc=/^(?:GET|HEAD)$/,Gc=/^\/\//,Hc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ic={},Jc={},Kc="*/".concat("*");try{Ac=location.href}catch(Lc){Ac=z.createElement("a"),Ac.href="",Ac=Ac.href}zc=Hc.exec(Ac.toLowerCase())||[];function Mc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(F)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nc(a,b,c,d){var e={},f=a===Jc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Oc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Pc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Qc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ac,type:"GET",isLocal:Ec.test(zc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Oc(Oc(a,n.ajaxSettings),b):Oc(n.ajaxSettings,a)},ajaxPrefilter:Mc(Ic),ajaxTransport:Mc(Jc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Dc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||Ac)+"").replace(Bc,"").replace(Gc,zc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(F)||[""],null==k.crossDomain&&(c=Hc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===zc[1]&&c[2]===zc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(zc[3]||("http:"===zc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),Nc(Ic,k,b,v),2===t)return v;h=k.global,h&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Fc.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(xc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Cc.test(e)?e.replace(Cc,"$1_="+wc++):e+(xc.test(e)?"&":"?")+"_="+wc++)),k.ifModified&&(n.lastModified[e]&&v.setRequestHeader("If-Modified-Since",n.lastModified[e]),n.etag[e]&&v.setRequestHeader("If-None-Match",n.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Kc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Nc(Jc,k,b,v)){v.readyState=1,h&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Pc(k,v,c)),u=Qc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(n.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!l.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||n.css(a,"display"))},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var Rc=/%20/g,Sc=/\[\]$/,Tc=/\r?\n/g,Uc=/^(?:submit|button|image|reset|file)$/i,Vc=/^(?:input|select|textarea|keygen)/i;function Wc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Sc.test(a)?d(a,e):Wc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Wc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Wc(c,a[c],b,e);return d.join("&").replace(Rc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Vc.test(this.nodeName)&&!Uc.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Tc,"\r\n")}}):{name:b.name,value:c.replace(Tc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&$c()||_c()}:$c;var Xc=0,Yc={},Zc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Yc)Yc[a](void 0,!0)}),l.cors=!!Zc&&"withCredentials"in Zc,Zc=l.ajax=!!Zc,Zc&&n.ajaxTransport(function(a){if(!a.crossDomain||l.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Xc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Yc[g],b=void 0,f.onreadystatechange=n.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Yc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function $c(){try{return new a.XMLHttpRequest}catch(b){}}function _c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=z.head||n("head")[0]||z.documentElement;return{send:function(d,e){b=z.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var ad=[],bd=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=ad.pop()||n.expando+"_"+wc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(bd.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&bd.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(bd,"$1"+e):b.jsonp!==!1&&(b.url+=(xc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,ad.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||z;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var cd=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&cd)return cd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h,a.length),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&n.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n}); diff --git a/feincms/templates/admin/feincms/load-jquery.include b/feincms/templates/admin/feincms/load-jquery.include index aa922fe6e..ac93171b0 100644 --- a/feincms/templates/admin/feincms/load-jquery.include +++ b/feincms/templates/admin/feincms/load-jquery.include @@ -4,7 +4,7 @@ Include jquery, override this template if you want to use a cdn version or load more plugins or whatnot {% endcomment %} -<script type="text/javascript" src="{% static 'feincms/jquery-1.9.1.min.js' %}"></script> +<script type="text/javascript" src="{% static 'feincms/jquery-1.11.0.min.js' %}"></script> <script type="text/javascript" src="{% static 'feincms/jquery-ui-1.10.3.custom.min.js' %}"></script> <script type="text/javascript"> From c9b93c3637acaf396c78142d4e7c2b914e30a286 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Fri, 7 Feb 2014 15:43:06 +0100 Subject: [PATCH 0928/1590] It seems that the mptt engine in conjunction with a tight loop deleting items fails to correctly update mptt pointers. Thus just disable the mptt magic while deleting and then rebuild the tree afterwards. This is a rather heavy handed fix for the problem, revisit later. Should fix #514. --- feincms/admin/tree_editor.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 5a427a5e0..f6f2db8b8 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -526,16 +526,22 @@ def delete_selected_tree(self, modeladmin, request, queryset): # If this is True, the confirmation page has been displayed if request.POST.get('post'): n = 0 - for obj in queryset: - if self.has_delete_permission(request, obj): - obj.delete() - n += 1 - obj_display = force_text(obj) - self.log_deletion(request, obj, obj_display) - else: - logger.warning( - "Denied delete request by \"%s\" for object #%s", - request.user, obj.id) + # TODO: The disable_mptt_updates / rebuild is a work around + # for what seems to be a mptt problem when deleting items + # in a loop. Revisit this, there should be a better solution. + with queryset.model.objects.disable_mptt_updates(): + for obj in queryset: + if self.has_delete_permission(request, obj): + obj.delete() + n += 1 + obj_display = force_text(obj) + self.log_deletion(request, obj, obj_display) + else: + logger.warning( + "Denied delete request by \"%s\" for object #%s", + request.user, obj.id) + if n > 0: + queryset.model.objects.rebuild() self.message_user( request, _("Successfully deleted %(count)d items.") % {"count": n}) From 68f44f931baf581925d17608ea0726e0f8ca27ec Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Mon, 17 Feb 2014 15:02:15 +1100 Subject: [PATCH 0929/1590] Experimental sharing of content proxy --- feincms/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/feincms/models.py b/feincms/models.py index b3b1eaaaa..643bfb7d5 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -224,6 +224,13 @@ def _populate_content_type_caches(self, types): else: self._cache['cts'][cls] = [] + # share this content proxy object between all content items + # so that each can use obj.parent.content to determine its + # relationship to its siblings, etc. + for cls, objects in self._cache['cts'].items(): + for obj in objects: + setattr(obj.parent, '_content_proxy', self) + def _fetch_regions(self): """ Fetches all content types and group content types into regions From 7d09e20d99a8270bfa6fab12144a5fd97a3836b0 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Wed, 5 Mar 2014 14:26:50 +0100 Subject: [PATCH 0930/1590] Update Page.register_extension example in docs --- docs/page.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/page.rst b/docs/page.rst index d57566a9e..8ad7b9bc6 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -159,7 +159,9 @@ upon registering the extension. The :func:`register` method receives the :class:`~feincms.module.page.models.PageAdmin` as arguments. The extensions can be activated as follows:: - Page.register_extensions('navigation', 'titles', 'translations') + Page.register_extensions('feincms.module.page.extensions.navigation', + 'feincms.module.page.extensions.titles', + 'feincms.module.extensions.translations') The following extensions are available currently: From a8578c988627b13e6347f510041d82cf434686d9 Mon Sep 17 00:00:00 2001 From: Bojan Mihelac <bmihelac@mihelac.org> Date: Wed, 5 Mar 2014 14:45:27 +0100 Subject: [PATCH 0931/1590] Docs update - display full module path for extensions Shorthands were deprecated in FeinCMS 1.6 and removed in FeinCMS 1.8 --- docs/page.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/page.rst b/docs/page.rst index d57566a9e..a3e91b902 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -164,35 +164,35 @@ be activated as follows:: The following extensions are available currently: -* :mod:`~feincms.module.extensions.changedate` --- Creation and modification dates +* :mod:`feincms.module.extensions.changedate` --- Creation and modification dates Adds automatically maintained creation and modification date fields to the page. -* :mod:`~feincms.module.extensions.ct_tracker` --- Content type cache +* :mod:`feincms.module.extensions.ct_tracker` --- Content type cache Helps reduce database queries if you have three or more content types. -* :mod:`~feincms.module.extensions.datepublisher` --- Date-based publishing +* :mod:`feincms.module.extensions.datepublisher` --- Date-based publishing Adds publication date and end date fields to the page, thereby enabling the administrator to define a date range where a page will be available to website visitors. -* :mod:`~feincms.module.page.extensions.excerpt` --- Page summary +* :mod:`feincms.module.page.extensions.excerpt` --- Page summary Add a brief excerpt summarizing the content of this page. -* :mod:`~feincms.module.extensions.featured` --- Simple featured flag for a page +* :mod:`feincms.module.extensions.featured` --- Simple featured flag for a page Lets administrators set a featured flag that lets you treat that page special. -* :mod:`~feincms.module.page.extensions.navigation` --- Navigation extensions +* :mod:`feincms.module.page.extensions.navigation` --- Navigation extensions Adds navigation extensions to the page model. You can define subclasses of ``NavigationExtension``, which provide submenus to the navigation generation @@ -200,29 +200,29 @@ The following extensions are available currently: this extension. -* :mod:`~feincms.module.page.extensions.relatedpages` --- Links related content +* :mod:`feincms.module.page.extensions.relatedpages` --- Links related content Add a many-to-many relationship field to relate this page to other pages. -* :mod:`~feincms.module.extensions.seo` --- Search engine optimization +* :mod:`feincms.module.extensions.seo` --- Search engine optimization Adds fields to the page relevant for search engine optimization (SEO), currently only meta keywords and description. -* :mod:`~feincms.module.page.extensions.sites` --- Limit pages to sites +* :mod:`feincms.module.page.extensions.sites` --- Limit pages to sites Allows to limit a page to a certain site and not display it on other sites. -* :mod:`~feincms.module.page.extensions.symlinks` --- Symlinked content extension +* :mod:`feincms.module.page.extensions.symlinks` --- Symlinked content extension Sometimes you want to reuse all content from a page in another place. This extension lets you do that. -* :mod:`~feincms.module.page.extensions.titles` --- Additional titles +* :mod:`feincms.module.page.extensions.titles` --- Additional titles Adds additional title fields to the page model. You may not only define a single title for the page to be used in the navigation, the <title> tag and @@ -231,7 +231,7 @@ The following extensions are available currently: content area. -* :mod:`~feincms.module.extensions.translations` --- Page translations +* :mod:`feincms.module.extensions.translations` --- Page translations Adds a language field and a recursive translations many to many field to the page, so that you can define the language the page is in and assign From 33988b515e782b327204436f2a31a83df4169f6c Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Tue, 11 Mar 2014 22:35:40 +1100 Subject: [PATCH 0932/1590] Update model cache clearing to be compatible with Django 1.7. -- not thoroughly investigated, but seems to work... --- feincms/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index a472b6c55..283d0dc99 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -77,7 +77,10 @@ def ensure_completely_loaded(force=False): # a model validation error (Django 1.4 doesn't exhibit this problem). # See Issue #323 on github. if hasattr(loading, 'cache'): - loading.cache._get_models_cache.clear() + try: + loading.cache.get_models.cache_clear() # Django 1.7+ + except AttributeError: + loading.cache._get_models_cache.clear() # Django 1.6- if hasattr(loading.app_cache_ready, '__call__'): if loading.app_cache_ready(): From d3a3d3278af6f75716d36a2cd495e828c90bcea9 Mon Sep 17 00:00:00 2001 From: Marc Egli <frog32@me.com> Date: Wed, 19 Mar 2014 13:59:30 +0100 Subject: [PATCH 0933/1590] always test with the latest patch release --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index ea5c5150d..1e8ec7a2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,18 +5,18 @@ python: - "3.2" - "3.3" env: - - DJANGO_VERSION=1.4.10 - - DJANGO_VERSION=1.5.5 - - DJANGO_VERSION=1.6.0 + - DJANGO_REQUIREMENT="Django>=1.4,<1.5" + - DJANGO_REQUIREMENT="Django>=1.5,<1.6" + - DJANGO_REQUIREMENT="Django>=1.6,<1.7" matrix: exclude: - python: "3.2" - env: DJANGO_VERSION=1.4.10 + env: DJANGO_REQUIREMENT="Django>=1.4,<1.5" - python: "3.3" - env: DJANGO_VERSION=1.4.10 + env: DJANGO_REQUIREMENT="Django>=1.4,<1.5" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - - pip install -q Django==$DJANGO_VERSION django-mptt Pillow feedparser flake8 --use-mirrors + - pip install -q $DJANGO_REQUIREMENT django-mptt Pillow feedparser flake8 --use-mirrors - python setup.py -q install # command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && flake8 ." From 3d62864a8db2c04e0dd9803d9d602bf8018a1b9c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Mon, 24 Mar 2014 17:20:41 +0100 Subject: [PATCH 0934/1590] Prevent a crash in feincms_nav by returning early when page is None --- feincms/module/page/templatetags/feincms_page_tags.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 37c1ab8ce..07552077a 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -47,6 +47,9 @@ def feincms_nav(context, feincms_page, level=1, depth=1): page_class = _get_page_model() + if feincms_page is None: + return [] + if isinstance(feincms_page, HttpRequest): try: feincms_page = page_class.objects.for_request( From bd1bc99d7bf6072a8ccf8909487b1955b744e3c1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 27 Mar 2014 16:18:05 +0100 Subject: [PATCH 0935/1590] Fix #522: django.contrib.markup has been deprecated No strong preference for markdown, it's just that I remember the syntax :-) --- README.rst | 10 +++++----- docs/index.rst | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index a3976e2ba..77a99183d 100644 --- a/README.rst +++ b/README.rst @@ -39,27 +39,27 @@ else which I haven't thought of yet). It provides helper functions, which provide ordered lists of page content blocks. That's all. -Adding your own content types is extremely easy. Do you like textile +Adding your own content types is extremely easy. Do you like markdown that much, that you'd rather die than using a rich text editor? Then add the following code to your project, and you can go on using the CMS without being forced to use whatever the developers deemed best: :: + from markdown2 import markdown from feincms.module.page.models import Page - from django.contrib.markup.templatetags.markup import textile from django.db import models - class TextilePageContent(models.Model): + class MarkdownPageContent(models.Model): content = models.TextField() class Meta: abstract = True def render(self, **kwargs): - return textile(self.content) + return markdown(self.content) - Page.create_content_type(TextilePageContent) + Page.create_content_type(MarkdownPageContent) That's it. Not even ten code lines for your own page content type. diff --git a/docs/index.rst b/docs/index.rst index 7b92fbaae..8de27dde6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -15,25 +15,25 @@ to a region (f.e. the sidebar, the main content region or something else which I haven't thought of yet). It provides helper functions, which provide ordered lists of page content blocks. That's all. -Adding your own content types is extremely easy. Do you like textile +Adding your own content types is extremely easy. Do you like markdown that much, that you'd rather die than using a rich text editor? Then add the following code to your project, and you can go on using the CMS without being forced to use whatever the developers deemed best:: + from markdown2 import markdown from feincms.module.page.models import Page - from django.contrib.markup.templatetags.markup import textile from django.db import models - class TextilePageContent(models.Model): + class MarkdownPageContent(models.Model): content = models.TextField() class Meta: abstract = True def render(self, **kwargs): - return textile(self.content) + return markdown(self.content) - Page.create_content_type(TextilePageContent) + Page.create_content_type(MarkdownPageContent) That's it. Only ten lines of code for your own page content type. From f524bc3a541f4e0e9aaa0a5ecc2225a56a8bbead Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 27 Mar 2014 16:19:12 +0100 Subject: [PATCH 0936/1590] More copy-pasting --- docs/contenttypes.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 4c6e08551..4a45b7ae4 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -82,23 +82,23 @@ in the rendered result. outlined apply for all other CMS base types. -The complete code required to implement and include a custom textile content +The complete code required to implement and include a custom markdown content type is shown here:: + from markdown2 import markdown from feincms.module.page.models import Page - from django.contrib.markup.templatetags.markup import textile from django.db import models - class TextilePageContent(models.Model): + class MarkdownPageContent(models.Model): content = models.TextField() class Meta: abstract = True def render(self, **kwargs): - return textile(self.content) + return markdown(self.content) - Page.create_content_type(TextilePageContent) + Page.create_content_type(MarkdownPageContent) There are three field names you should not use because they are added @@ -435,18 +435,18 @@ Other rich text libraries ~~~~~~~~~~~~~~~~~~~~~~~~~ Other rich text widgets can be wired up for the RichTextContent. -You would have to write two functions: One which is called when -rich text editing functionality is added ("richify"), and another -one which is called when functionality is removed ("poorify"). -The second is necessary because rich text editors do not like -being dragged; when dragging a rich text content type, it is first -poorified and then richified again as soon as the content type has +You would have to write two functions: One which is called when +rich text editing functionality is added ("richify"), and another +one which is called when functionality is removed ("poorify"). +The second is necessary because rich text editors do not like +being dragged; when dragging a rich text content type, it is first +poorified and then richified again as soon as the content type has been dropped into its final position. To perform those operations * Add a function adding the new rich text editor to ``contentblock_init_handlers`` and to ``contentblock_move_handlers.richify`` - * Add a function removing the rich text editor to + * Add a function removing the rich text editor to ``contentblock_move_handlers.poorify`` From 47502d4b500351924d62afd352fe51edd1d201bf Mon Sep 17 00:00:00 2001 From: Simon Meers <simon@simonmeers.com> Date: Tue, 8 Apr 2014 15:02:35 +1000 Subject: [PATCH 0937/1590] prevent PageAdminForm from blowing up if passed instance=None --- feincms/module/page/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index f15d083e9..f8e043ebc 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -127,7 +127,7 @@ def __init__(self, *args, **kwargs): template = self.page_model._feincms_templates[key] pages_for_template = self.page_model._default_manager.filter( template_key=key) - pk = kwargs['instance'].pk if 'instance' in kwargs else None + pk = kwargs['instance'].pk if kwargs.get('instance') else None other_pages_for_template = pages_for_template.exclude(pk=pk) if template.singleton and other_pages_for_template.exists(): continue # don't allow selection of singleton if in use From ab2941c2a9cec59e5776e04ec781b264a588fe97 Mon Sep 17 00:00:00 2001 From: Sun Liwen <sunliwen@gmail.com> Date: Thu, 10 Apr 2014 00:31:35 +0800 Subject: [PATCH 0938/1590] Update docs to mention modeladmins --- docs/page.rst | 2 +- docs/versioning.rst | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/page.rst b/docs/page.rst index 5676449e5..513be9f1d 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -156,7 +156,7 @@ cluttering up the core page model for those who do not need them. The extensions are standard python modules with a :func:`register` method which will be called upon registering the extension. The :func:`register` method receives the :class:`~feincms.module.page.models.Page` class itself and the model admin class -:class:`~feincms.module.page.models.PageAdmin` as arguments. The extensions can +:class:`~feincms.module.page.modeladmins.PageAdmin` as arguments. The extensions can be activated as follows:: Page.register_extensions('feincms.module.page.extensions.navigation', diff --git a/docs/versioning.rst b/docs/versioning.rst index a10cf19bf..462ad6ff6 100644 --- a/docs/versioning.rst +++ b/docs/versioning.rst @@ -19,7 +19,8 @@ Now, you need to create your own model admin subclass inheriting from both FeinCMS' ``PageAdmin`` and from reversions ``VersionAdmin``:: from django.contrib import admin - from feincms.module.page.models import Page, PageAdmin + from feincms.module.page.models import Page + from feincms.module.page.modeladmins import PageAdmin from reversion.admin import VersionAdmin admin.site.unregister(Page) From b6c0d066aff1d00d1780d165922e728fc095ebdb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 12 Apr 2014 17:35:09 +0200 Subject: [PATCH 0939/1590] Fix all flake8 2.1.0 warnings --- feincms/__init__.py | 4 ++-- feincms/admin/item_editor.py | 2 +- feincms/admin/tree_editor.py | 2 +- feincms/content/comments/models.py | 4 ++-- feincms/models.py | 4 ++-- feincms/module/extensions/ct_tracker.py | 2 +- feincms/module/medialibrary/modeladmins.py | 4 ++-- feincms/module/medialibrary/models.py | 2 -- feincms/module/mixins.py | 2 +- feincms/module/page/extensions/navigation.py | 2 +- feincms/module/page/modeladmins.py | 4 ++-- feincms/module/page/processors.py | 2 +- feincms/utils/__init__.py | 4 ++-- tests/testapp/tests/test_cms.py | 12 ++++++------ tests/testapp/tests/test_page.py | 2 +- 15 files changed, 25 insertions(+), 27 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 283d0dc99..18988f812 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -78,9 +78,9 @@ def ensure_completely_loaded(force=False): # See Issue #323 on github. if hasattr(loading, 'cache'): try: - loading.cache.get_models.cache_clear() # Django 1.7+ + loading.cache.get_models.cache_clear() # Django 1.7+ except AttributeError: - loading.cache._get_models_cache.clear() # Django 1.6- + loading.cache._get_models_cache.clear() # Django 1.6- if hasattr(loading.app_cache_ready, '__call__'): if loading.app_cache_ready(): diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 86cf750aa..731512029 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -333,7 +333,7 @@ def get_fieldsets(self, request, obj=None): fieldsets = copy.deepcopy( super(ItemEditor, self).get_fieldsets(request, obj)) - if not FEINCMS_CONTENT_FIELDSET_NAME in dict(fieldsets).keys(): + if FEINCMS_CONTENT_FIELDSET_NAME not in dict(fieldsets).keys(): fieldsets.append(FEINCMS_CONTENT_FIELDSET) return fieldsets diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index f6f2db8b8..1aa4c3473 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -353,7 +353,7 @@ def _toggle_boolean(self, request): self._collect_editable_booleans() - if not attr in self._ajax_editable_booleans: + if attr not in self._ajax_editable_booleans: return HttpResponseBadRequest("not a valid attribute %s" % attr) try: diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index be7f7a45f..3ad59260c 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -81,8 +81,8 @@ def process(self, request, **kwargs): # post to the current path and handle it this way .. at least it # works for now. - #extra = request._feincms_extra_context.get('page_extra_path', ()) - #if len(extra) > 0 and extra[0] == "post-comment": + # extra = request._feincms_extra_context.get('page_extra_path', ()) + # if len(extra) > 0 and extra[0] == "post-comment": r = post_comment(request, next=comment_page.get_absolute_url()) diff --git a/feincms/models.py b/feincms/models.py index 643bfb7d5..225111a0e 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -412,8 +412,8 @@ def _template(self): cls.template = property(_template) cls.TEMPLATE_CHOICES = field._choices = [ - (template.key, template.title,) - for template in cls._feincms_templates.values() + (template_.key, template_.title,) + for template_ in cls._feincms_templates.values() ] field.default = field.choices[0][0] diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 05ef06f40..2065a45c4 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -79,7 +79,7 @@ def _fetch_content_type_counts(self): def _translation_map(self): cls = self.item.__class__ - if not cls in _translation_map_cache: + if cls not in _translation_map_cache: # Prime translation map and cache it in the class. This needs to be # done late as opposed to at class definition time as not all # information is ready, especially when we are doing a "syncdb" the diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 4a43c198d..7c8c390a0 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -42,7 +42,7 @@ class CategoryAdmin(admin.ModelAdmin): prepopulated_fields = {'slug': ('title',)} -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------ def assign_category(modeladmin, request, queryset): class AddCategoryForm(forms.Form): _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) @@ -84,7 +84,7 @@ class AddCategoryForm(forms.Form): assign_category.short_description = _('Add selected media files to category') -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- def save_as_zipfile(modeladmin, request, queryset): from .zip import export_zipfile diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index c4f19a766..0ef9debd8 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -267,5 +267,3 @@ class Meta: def __str__(self): return self.caption - -#------------------------------------------------------------------------- diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 792576141..9eefea0cd 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -44,7 +44,7 @@ def register_response_processor(cls, fn, key=None): cls.response_processors = SortedDict() cls.response_processors[fn if key is None else key] = fn - # Implement admin_urlname templatetag protocol + # TODO Implement admin_urlname templatetag protocol @property def app_label(self): """ diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index c64ec0362..3edb296b2 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -101,7 +101,7 @@ def children(self, page, **kwargs): def navigation_extension_choices(): for ext in NavigationExtension.types: if (issubclass(ext, NavigationExtension) - and not ext is NavigationExtension): + and ext is not NavigationExtension): yield ('%s.%s' % (ext.__module__, ext.__name__), ext.name) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 80607d575..3a6325fb7 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -215,14 +215,14 @@ def is_visible_admin(self, page): # Sanity check in case this is not already defined self._visible_pages = list() - if page.parent_id and not page.parent_id in self._visible_pages: + if page.parent_id and page.parent_id not in self._visible_pages: # parent page's invisibility is inherited if page.id in self._visible_pages: self._visible_pages.remove(page.id) return tree_editor.ajax_editable_boolean_cell( page, 'active', override=False, text=_('inherited')) - if page.active and not page.id in self._visible_pages: + if page.active and page.id not in self._visible_pages: # is active but should not be shown, so visibility limited by # extension: show a "not active" return tree_editor.ajax_editable_boolean_cell( diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 1a51565e0..18e3573e3 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -47,7 +47,7 @@ def frontendediting_request_processor(page, request): Sets the frontend editing state in the cookie depending on the ``frontend_editing`` GET parameter and the user's permissions. """ - if not 'frontend_editing' in request.GET: + if 'frontend_editing' not in request.GET: return response = HttpResponseRedirect(request.path) diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 27a0c1bd6..dc9c69f27 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -58,8 +58,8 @@ def copy_model_instance(obj, exclude=None): exclude = exclude or () initial = dict( (f.name, getattr(obj, f.name)) for f in obj._meta.fields - if not isinstance(f, AutoField) and not f.name in exclude - and not f in obj._meta.parents.values()) + if not isinstance(f, AutoField) and f.name not in exclude + and f not in obj._meta.parents.values()) return obj.__class__(**initial) diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 1cc564ca7..1b6ae0f03 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -79,11 +79,11 @@ def _new_parse(link): self.assertTrue('yahoo' in obj.render()) - #Creating a content type twice isn't forbidden anymore - #def test_03_double_creation(self): - # # creating a content type twice is forbidden - # self.assertRaises(ImproperlyConfigured, - # lambda: ExampleCMSBase.create_content_type(RawContent)) + # Creating a content type twice isn't forbidden anymore + # def test_03_double_creation(self): + # # creating a content type twice is forbidden + # self.assertRaises(ImproperlyConfigured, + # lambda: ExampleCMSBase.create_content_type(RawContent)) def test_04_mediafilecontent_creation(self): # the medialibrary needs to be enabled, otherwise this test fails @@ -173,7 +173,7 @@ class Attachment(models.Model): self.assertTrue(Attachment in related_models) self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) - #self.assertFalse(hasattr(Attachment, 'anycontents')) + # self.assertFalse(hasattr(Attachment, 'anycontents')) class AnyContent(models.Model): attachment = models.ForeignKey( diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index d18fe3228..eab8b59f8 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -342,7 +342,7 @@ def create_page_through_admincontent(self, page, **kwargs): data = { 'title': page.title, 'slug': page.slug, - #'parent': page.parent_id, # this field is excluded from the form + # 'parent': page.parent_id, # this field is excluded from the form 'template_key': page.template_key, 'publication_date_0': '2009-01-01', 'publication_date_1': '00:00:00', From 1016afc80984336c7c9057f43aac727a35d7269e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 12 Apr 2014 17:35:09 +0200 Subject: [PATCH 0940/1590] Fix all flake8 2.1.0 warnings Conflicts: feincms/__init__.py --- feincms/admin/item_editor.py | 2 +- feincms/admin/tree_editor.py | 2 +- feincms/content/comments/models.py | 4 ++-- feincms/models.py | 4 ++-- feincms/module/extensions/ct_tracker.py | 2 +- feincms/module/medialibrary/modeladmins.py | 4 ++-- feincms/module/medialibrary/models.py | 2 -- feincms/module/mixins.py | 2 +- feincms/module/page/extensions/navigation.py | 2 +- feincms/module/page/modeladmins.py | 4 ++-- feincms/module/page/processors.py | 2 +- feincms/utils/__init__.py | 4 ++-- tests/testapp/tests/test_cms.py | 12 ++++++------ tests/testapp/tests/test_page.py | 2 +- 14 files changed, 23 insertions(+), 25 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 86cf750aa..731512029 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -333,7 +333,7 @@ def get_fieldsets(self, request, obj=None): fieldsets = copy.deepcopy( super(ItemEditor, self).get_fieldsets(request, obj)) - if not FEINCMS_CONTENT_FIELDSET_NAME in dict(fieldsets).keys(): + if FEINCMS_CONTENT_FIELDSET_NAME not in dict(fieldsets).keys(): fieldsets.append(FEINCMS_CONTENT_FIELDSET) return fieldsets diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 5a427a5e0..c4bb00a44 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -353,7 +353,7 @@ def _toggle_boolean(self, request): self._collect_editable_booleans() - if not attr in self._ajax_editable_booleans: + if attr not in self._ajax_editable_booleans: return HttpResponseBadRequest("not a valid attribute %s" % attr) try: diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index be7f7a45f..3ad59260c 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -81,8 +81,8 @@ def process(self, request, **kwargs): # post to the current path and handle it this way .. at least it # works for now. - #extra = request._feincms_extra_context.get('page_extra_path', ()) - #if len(extra) > 0 and extra[0] == "post-comment": + # extra = request._feincms_extra_context.get('page_extra_path', ()) + # if len(extra) > 0 and extra[0] == "post-comment": r = post_comment(request, next=comment_page.get_absolute_url()) diff --git a/feincms/models.py b/feincms/models.py index 9286047cc..2b6021f7a 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -405,8 +405,8 @@ def _template(self): cls.template = property(_template) cls.TEMPLATE_CHOICES = field._choices = [ - (template.key, template.title,) - for template in cls._feincms_templates.values() + (template_.key, template_.title,) + for template_ in cls._feincms_templates.values() ] field.default = field.choices[0][0] diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 05ef06f40..2065a45c4 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -79,7 +79,7 @@ def _fetch_content_type_counts(self): def _translation_map(self): cls = self.item.__class__ - if not cls in _translation_map_cache: + if cls not in _translation_map_cache: # Prime translation map and cache it in the class. This needs to be # done late as opposed to at class definition time as not all # information is ready, especially when we are doing a "syncdb" the diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 4a43c198d..7c8c390a0 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -42,7 +42,7 @@ class CategoryAdmin(admin.ModelAdmin): prepopulated_fields = {'slug': ('title',)} -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------ def assign_category(modeladmin, request, queryset): class AddCategoryForm(forms.Form): _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) @@ -84,7 +84,7 @@ class AddCategoryForm(forms.Form): assign_category.short_description = _('Add selected media files to category') -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- def save_as_zipfile(modeladmin, request, queryset): from .zip import export_zipfile diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index c4f19a766..0ef9debd8 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -267,5 +267,3 @@ class Meta: def __str__(self): return self.caption - -#------------------------------------------------------------------------- diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 792576141..9eefea0cd 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -44,7 +44,7 @@ def register_response_processor(cls, fn, key=None): cls.response_processors = SortedDict() cls.response_processors[fn if key is None else key] = fn - # Implement admin_urlname templatetag protocol + # TODO Implement admin_urlname templatetag protocol @property def app_label(self): """ diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index c64ec0362..3edb296b2 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -101,7 +101,7 @@ def children(self, page, **kwargs): def navigation_extension_choices(): for ext in NavigationExtension.types: if (issubclass(ext, NavigationExtension) - and not ext is NavigationExtension): + and ext is not NavigationExtension): yield ('%s.%s' % (ext.__module__, ext.__name__), ext.name) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 80607d575..3a6325fb7 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -215,14 +215,14 @@ def is_visible_admin(self, page): # Sanity check in case this is not already defined self._visible_pages = list() - if page.parent_id and not page.parent_id in self._visible_pages: + if page.parent_id and page.parent_id not in self._visible_pages: # parent page's invisibility is inherited if page.id in self._visible_pages: self._visible_pages.remove(page.id) return tree_editor.ajax_editable_boolean_cell( page, 'active', override=False, text=_('inherited')) - if page.active and not page.id in self._visible_pages: + if page.active and page.id not in self._visible_pages: # is active but should not be shown, so visibility limited by # extension: show a "not active" return tree_editor.ajax_editable_boolean_cell( diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 1a51565e0..18e3573e3 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -47,7 +47,7 @@ def frontendediting_request_processor(page, request): Sets the frontend editing state in the cookie depending on the ``frontend_editing`` GET parameter and the user's permissions. """ - if not 'frontend_editing' in request.GET: + if 'frontend_editing' not in request.GET: return response = HttpResponseRedirect(request.path) diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 27a0c1bd6..dc9c69f27 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -58,8 +58,8 @@ def copy_model_instance(obj, exclude=None): exclude = exclude or () initial = dict( (f.name, getattr(obj, f.name)) for f in obj._meta.fields - if not isinstance(f, AutoField) and not f.name in exclude - and not f in obj._meta.parents.values()) + if not isinstance(f, AutoField) and f.name not in exclude + and f not in obj._meta.parents.values()) return obj.__class__(**initial) diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 1cc564ca7..1b6ae0f03 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -79,11 +79,11 @@ def _new_parse(link): self.assertTrue('yahoo' in obj.render()) - #Creating a content type twice isn't forbidden anymore - #def test_03_double_creation(self): - # # creating a content type twice is forbidden - # self.assertRaises(ImproperlyConfigured, - # lambda: ExampleCMSBase.create_content_type(RawContent)) + # Creating a content type twice isn't forbidden anymore + # def test_03_double_creation(self): + # # creating a content type twice is forbidden + # self.assertRaises(ImproperlyConfigured, + # lambda: ExampleCMSBase.create_content_type(RawContent)) def test_04_mediafilecontent_creation(self): # the medialibrary needs to be enabled, otherwise this test fails @@ -173,7 +173,7 @@ class Attachment(models.Model): self.assertTrue(Attachment in related_models) self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) - #self.assertFalse(hasattr(Attachment, 'anycontents')) + # self.assertFalse(hasattr(Attachment, 'anycontents')) class AnyContent(models.Model): attachment = models.ForeignKey( diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 91d3c77f7..f583f6350 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -342,7 +342,7 @@ def create_page_through_admincontent(self, page, **kwargs): data = { 'title': page.title, 'slug': page.slug, - #'parent': page.parent_id, # this field is excluded from the form + # 'parent': page.parent_id, # this field is excluded from the form 'template_key': page.template_key, 'publication_date_0': '2009-01-01', 'publication_date_1': '00:00:00', From d3e6296e371e53061d79a8421d0d9a802d258fee Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:10:08 +0200 Subject: [PATCH 0941/1590] Wait to run the body of ensure_completely_loaded until the app registry is ready --- feincms/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feincms/__init__.py b/feincms/__init__.py index 18988f812..18537bfba 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -44,6 +44,10 @@ def ensure_completely_loaded(force=False): if COMPLETELY_LOADED and not force: return True + from django.apps import apps + if not apps.ready: + return + # Ensure meta information concerning related fields is up-to-date. # Upon accessing the related fields information from Model._meta, # the related fields are cached and never refreshed again (because From b23ab61bfbf4a0a7f296e44a665bb379e5e28f0b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:10:36 +0200 Subject: [PATCH 0942/1590] Backport of get_permission_codename for Django versions<1.7 --- feincms/_internal.py | 8 ++++++++ feincms/admin/item_editor.py | 3 ++- feincms/admin/tree_editor.py | 7 ++++--- feincms/templatetags/feincms_tags.py | 4 +++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/feincms/_internal.py b/feincms/_internal.py index 5109a9d32..0f1a7666c 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -55,3 +55,11 @@ def <method2>(...): ... if name != "__metaclass__": setattr(base, name, value) return base + + +def get_permission_codename(action, opts): + """ + Backport of django.contrib.auth.get_permission_codename for older versions + of Django. + """ + return '%s_%s' % (action, opts.model_name) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 731512029..785317369 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -21,6 +21,7 @@ from django.utils.translation import ugettext as _ from feincms import settings, ensure_completely_loaded +from feincms._internal import get_permission_codename from feincms.extensions import ExtensionModelAdmin from feincms.signals import itemeditor_post_save_related from feincms.templatetags.feincms_admin_tags import is_popup_var @@ -90,7 +91,7 @@ def append_feincms_inlines(self, inline_instances, request): def can_add_content(self, request, content_type): perm = '.'.join(( content_type._meta.app_label, - content_type._meta.get_add_permission())) + get_permission_codename('add', content_type._meta))) return request.user.has_perm(perm) def get_feincms_inlines(self, model, request): diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 1aa4c3473..3578b00a7 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -24,6 +24,7 @@ from mptt.forms import MPTTAdminForm from feincms import settings +from feincms._internal import get_permission_codename from feincms.extensions import ExtensionModelAdmin @@ -246,11 +247,11 @@ def __init__(self, *args, **kwargs): 'admin/feincms/tree_editor.html', ] self.object_change_permission =\ - opts.app_label + '.' + opts.get_change_permission() + opts.app_label + '.' + get_permission_codename('change', opts) self.object_add_permission =\ - opts.app_label + '.' + opts.get_add_permission() + opts.app_label + '.' + get_permission_codename('add', opts) self.object_delete_permission =\ - opts.app_label + '.' + opts.get_delete_permission() + opts.app_label + '.' + get_permission_codename('delete', opts) def changeable(self, item): return getattr(item, 'feincms_changeable', True) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 666db0bc0..571778153 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -10,6 +10,7 @@ from django.conf import settings from django.template.loader import render_to_string +from feincms._internal import get_permission_codename from feincms.utils import get_singleton, get_singleton_url @@ -88,7 +89,8 @@ def show_content_type_selection_widget(context, region): ungrouped = [] for ct in region._content_types: # Skip cts that we shouldn't be adding anyway - perm = ct._meta.app_label + "." + ct._meta.get_add_permission() + opts = ct._meta + perm = opts.app_label + "." + get_permission_codename('add', opts) if not user.has_perm(perm): continue From 189996f754cd5fa1186258230a0124ab058f888e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:11:08 +0200 Subject: [PATCH 0943/1590] Specify that admin model forms want all fields --- feincms/module/medialibrary/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index fc598f6c5..e592bd591 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -20,6 +20,7 @@ class MediaCategoryAdminForm(forms.ModelForm): class Meta: model = Category + fields = '__all__' def clean_parent(self): data = self.cleaned_data['parent'] @@ -40,6 +41,7 @@ class MediaFileAdminForm(forms.ModelForm): class Meta: model = MediaFile widgets = {'file': AdminFileWithPreviewWidget} + fields = '__all__' def __init__(self, *args, **kwargs): super(MediaFileAdminForm, self).__init__(*args, **kwargs) From a6e58598418756bf015f1e8194be8e17dbb7272a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:12:10 +0200 Subject: [PATCH 0944/1590] Use _meta.local_fields to find the template_key field The previous method, get_field_by_name depends on the app registry which is not ready at this point in time yet. Thanks to Marc Egli for the idea. --- feincms/models.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 225111a0e..487eca755 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -390,13 +390,17 @@ def register_templates(cls, *templates): instances[template.key] = template try: - field = cls._meta.get_field_by_name('template_key')[0] - except (FieldDoesNotExist, IndexError): + field = next(iter( + field for field in cls._meta.local_fields + if field.name == 'template_key')) + except (StopIteration,): cls.add_to_class( 'template_key', models.CharField(_('template'), max_length=255, choices=()) ) - field = cls._meta.get_field_by_name('template_key')[0] + field = next(iter( + field for field in cls._meta.local_fields + if field.name == 'template_key')) def _template(self): ensure_completely_loaded() From 2716c599a325375ce276f401871e6c2f83697daa Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:39:05 +0200 Subject: [PATCH 0945/1590] Use _meta.model_name and fall back to _meta.module_name --- feincms/_internal.py | 7 +++++++ feincms/content/comments/models.py | 3 ++- feincms/management/checker.py | 6 ++++-- feincms/models.py | 3 ++- feincms/module/mixins.py | 5 +++++ feincms/module/page/forms.py | 7 ++++--- feincms/module/page/models.py | 4 ++-- 7 files changed, 26 insertions(+), 9 deletions(-) diff --git a/feincms/_internal.py b/feincms/_internal.py index 0f1a7666c..cb7acac40 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -63,3 +63,10 @@ def get_permission_codename(action, opts): of Django. """ return '%s_%s' % (action, opts.model_name) + + +def get_model_name(opts): + try: + return opts.model_name + except AttributeError: + return opts.module_name diff --git a/feincms/content/comments/models.py b/feincms/content/comments/models.py index 3ad59260c..6d10bf344 100644 --- a/feincms/content/comments/models.py +++ b/feincms/content/comments/models.py @@ -23,6 +23,7 @@ from django.utils.translation import ugettext_lazy as _ from feincms.admin.item_editor import ItemEditorForm +from feincms._internal import get_model_name # ------------------------------------------------------------------------ @@ -59,7 +60,7 @@ def __init__(self, *args, **kwargs): _('public') if c.is_public else _('not public')), 'app': comments_model._meta.app_label, - 'model': comments_model._meta.module_name, + 'model': get_model_name(comments_model._meta), } f.help_text = r diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 3336d4c25..40ba55022 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -3,8 +3,10 @@ from django.core.management.color import color_style from django.db import connection +from feincms._internal import get_model_name -def check_database_schema(cls, module_name): + +def check_database_schema(cls, model_name): """ Returns a function which inspects the database table of the passed class. It checks whether all fields in the model are available on the database @@ -23,7 +25,7 @@ def check_database_schema(cls, module_name): """ def _fn(sender, **kwargs): - if sender.__name__ != module_name: + if sender.__name__ != model_name: return cursor = connection.cursor() diff --git a/feincms/models.py b/feincms/models.py index 487eca755..9e78815cb 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -25,6 +25,7 @@ from django.utils.translation import ugettext_lazy as _ from feincms import ensure_completely_loaded +from feincms._internal import get_model_name from feincms.extensions import ExtensionsMixin from feincms.utils import copy_model_instance @@ -521,7 +522,7 @@ def fe_identifier(self): return '%s-%s-%s-%s-%s' % ( cls._meta.app_label, - cls._meta.module_name, + get_model_name(cls._meta), self.__class__.__name__.lower(), self.parent_id, self.id, diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index 9eefea0cd..3c7a9e67e 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -55,6 +55,11 @@ def app_label(self): """ return self._meta.app_label + @property + def model_name(self): + "See app_label" + return self.__class__.__name__.lower() + @property def module_name(self): "See app_label" diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index f8e043ebc..228feeb71 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -15,6 +15,7 @@ from django.utils.translation import ugettext_lazy as _ from feincms import ensure_completely_loaded +from feincms._internal import get_model_name from mptt.forms import MPTTAdminForm @@ -23,12 +24,12 @@ class RedirectToWidget(ForeignKeyRawIdWidget): def label_for_value(self, value): match = re.match( # XXX this regex would be available as .models.REDIRECT_TO_RE - r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$', + r'^(?P<app_label>\w+).(?P<model_name>\w+):(?P<pk>\d+)$', value) if match: matches = match.groupdict() - model = get_model(matches['app_label'], matches['module_name']) + model = get_model(matches['app_label'], matches['model_name']) try: instance = model._default_manager.get(pk=int(matches['pk'])) return ' <strong>%s (%s)</strong>' % ( @@ -169,7 +170,7 @@ def clean(self): if redirect_to and re.match(r'^\d+$', redirect_to): opts = self.page_model._meta cleaned_data['redirect_to'] = '%s.%s:%s' % ( - opts.app_label, opts.module_name, redirect_to) + opts.app_label, get_model_name(opts), redirect_to) if not cleaned_data['active']: # If the current item is inactive, we do not need to conduct diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c23bf5bfe..7675afe03 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -29,7 +29,7 @@ REDIRECT_TO_RE = re.compile( - r'^(?P<app_label>\w+).(?P<module_name>\w+):(?P<pk>\d+)$') + r'^(?P<app_label>\w+).(?P<model_name>\w+):(?P<pk>\d+)$') # ------------------------------------------------------------------------ @@ -381,7 +381,7 @@ def get_redirect_to_target(self, request): return self.redirect_to matches = match.groupdict() - model = get_model(matches['app_label'], matches['module_name']) + model = get_model(matches['app_label'], matches['model_name']) if not model: return self.redirect_to From 0039fcc81ce9a181e95bd610ce299ae301da7e4c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:42:25 +0200 Subject: [PATCH 0946/1590] ModelAdmin.queryset has been renamed to ModelAdmin.get_queryset --- feincms/admin/tree_editor.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 3578b00a7..be2228c37 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -424,7 +424,9 @@ def changelist_view(self, request, extra_context=None, *args, **kwargs): self._refresh_changelist_caches() extra_context = extra_context or {} - queryset = self.queryset(request) + queryset = ( + self.get_queryset(request) if hasattr(self, 'get_queryset') + else self.queryset(request)) extra_context['tree_structure'] = mark_safe( json.dumps(_build_tree_structure(queryset))) @@ -478,7 +480,9 @@ def _move_node(self, request): else: tree_manager = self.model._tree_manager - queryset = self.queryset(request) + queryset = ( + self.get_queryset(request) if hasattr(self, 'get_queryset') + else self.queryset(request)) cut_item = queryset.get(pk=request.POST.get('cut_item')) pasted_on = queryset.get(pk=request.POST.get('pasted_on')) position = request.POST.get('position') From c7213cd844e1905bf0276eab6cc9ba753491cfca Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:44:47 +0200 Subject: [PATCH 0947/1590] django.apps only exists in Django 1.7 and up --- feincms/__init__.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 18537bfba..ebd94ddf5 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -44,9 +44,14 @@ def ensure_completely_loaded(force=False): if COMPLETELY_LOADED and not force: return True - from django.apps import apps - if not apps.ready: - return + try: + from django.apps import apps + except ImportError: + pass + else: + # Django 1.7 and up + if not apps.ready: + return # Ensure meta information concerning related fields is up-to-date. # Upon accessing the related fields information from Model._meta, From e6dc91a3a15214dfe58311334036bace878af543 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:47:05 +0200 Subject: [PATCH 0948/1590] Start the uglyness. Django < 1.7 cannot handle fields = '__all__' --- feincms/module/medialibrary/forms.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index e592bd591..fbde78608 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -6,6 +6,7 @@ import os +import django from django import forms from django.utils.translation import ugettext_lazy as _ @@ -20,7 +21,8 @@ class MediaCategoryAdminForm(forms.ModelForm): class Meta: model = Category - fields = '__all__' + if django.VERSION > (1, 7): + fields = '__all__' def clean_parent(self): data = self.cleaned_data['parent'] @@ -41,7 +43,8 @@ class MediaFileAdminForm(forms.ModelForm): class Meta: model = MediaFile widgets = {'file': AdminFileWithPreviewWidget} - fields = '__all__' + if django.VERSION > (1, 7): + fields = '__all__' def __init__(self, *args, **kwargs): super(MediaFileAdminForm, self).__init__(*args, **kwargs) From b376e75be5825ba7c86b51fde3dce68e01c7ac1f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:47:23 +0200 Subject: [PATCH 0949/1590] Use get_model_name inside get_permission_codename instead of crashing --- feincms/_internal.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/feincms/_internal.py b/feincms/_internal.py index cb7acac40..108db6149 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -57,16 +57,16 @@ def <method2>(...): ... return base -def get_permission_codename(action, opts): - """ - Backport of django.contrib.auth.get_permission_codename for older versions - of Django. - """ - return '%s_%s' % (action, opts.model_name) - - def get_model_name(opts): try: return opts.model_name except AttributeError: return opts.module_name + + +def get_permission_codename(action, opts): + """ + Backport of django.contrib.auth.get_permission_codename for older versions + of Django. + """ + return '%s_%s' % (action, get_model_name(opts)) From 400ec9856ce2f357136e9c801db8b8c7e72d613d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 10:48:39 +0200 Subject: [PATCH 0950/1590] Unfunnily, Django 1.7 requires django-mptt-dev --- tests/tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tox.ini b/tests/tox.ini index 2be18e98c..ef0302ed7 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -86,7 +86,7 @@ deps = basepython = python2.7 deps = --editable=git+git://github.com/django/django.git@master#egg=django-dev - django-mptt==0.6.0 + --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 @@ -116,7 +116,7 @@ deps = basepython = python3.2 deps = --editable=git+git://github.com/django/django.git@master#egg=django-dev - django-mptt==0.6.0 + --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 @@ -146,7 +146,7 @@ deps = basepython = python3.3 deps = --editable=git+git://github.com/django/django.git@master#egg=django-dev - django-mptt==0.6.0 + --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev Pillow==2.2.1 feedparser==5.1.3 lxml==3.2.3 From 4020e1ac32f741cbad76deccaa18933308b1630a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 11:31:41 +0200 Subject: [PATCH 0951/1590] Move Page initialization code into the models file --- tests/testapp/models.py | 10 +++++++++- tests/testapp/tests/test_stuff.py | 12 ------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 668202fc1..25b67c7b1 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -12,8 +12,11 @@ from feincms.content.image.models import ImageContent from feincms.content.medialibrary.models import MediaFileContent from feincms.content.application.models import ApplicationContent +from feincms.content.contactform.models import ContactFormContent, ContactForm +from feincms.content.file.models import FileContent from feincms.module.page.extensions.navigation import ( NavigationExtension, PagePretender) +from feincms.module.page import processors from feincms.content.application.models import reverse from mptt.models import MPTTModel @@ -41,6 +44,12 @@ ('default', 'Default position'), ) ) +Page.create_content_type(ContactFormContent, form=ContactForm) +Page.create_content_type(FileContent) +Page.register_request_processor(processors.etag_request_processor) +Page.register_response_processor(processors.etag_response_processor) +Page.register_response_processor( + processors.debug_sql_queries_response_processor()) def get_admin_fields(form, *args, **kwargs): @@ -56,7 +65,6 @@ def get_admin_fields(form, *args, **kwargs): 'custom_field': forms.CharField(), } - Page.create_content_type( ApplicationContent, APPLICATIONS=( diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 3fdf06fe2..3086e38e3 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -11,13 +11,8 @@ from django.utils.encoding import force_text import feincms - -from feincms.content.contactform.models import ContactFormContent, ContactForm -from feincms.content.file.models import FileContent - from feincms.models import Region, Template, Base from feincms.module.blog.models import Entry -from feincms.module.page import processors from feincms.module.page.models import Page from feincms.utils import collect_dict_values, get_object, shorten_string @@ -107,13 +102,6 @@ class ExampleCMSBase2(Base): ('region', 'region title'), ('region2', 'region2 title')) -Page.create_content_type(ContactFormContent, form=ContactForm) -Page.create_content_type(FileContent) -Page.register_request_processor(processors.etag_request_processor) -Page.register_response_processor(processors.etag_response_processor) -Page.register_response_processor( - processors.debug_sql_queries_response_processor()) - class BlogTestCase(TestCase): def setUp(self): From 05a8cde1d009240bd07a0a6c8cd4cde907eaf185 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 11:32:39 +0200 Subject: [PATCH 0952/1590] Remove two unused imports --- feincms/management/checker.py | 2 -- tests/testapp/tests/test_stuff.py | 1 - 2 files changed, 3 deletions(-) diff --git a/feincms/management/checker.py b/feincms/management/checker.py index 40ba55022..8c157e284 100644 --- a/feincms/management/checker.py +++ b/feincms/management/checker.py @@ -3,8 +3,6 @@ from django.core.management.color import color_style from django.db import connection -from feincms._internal import get_model_name - def check_database_schema(cls, model_name): """ diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 3086e38e3..ad2283065 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -13,7 +13,6 @@ import feincms from feincms.models import Region, Template, Base from feincms.module.blog.models import Entry -from feincms.module.page.models import Page from feincms.utils import collect_dict_values, get_object, shorten_string From dcc1ebcb4d1a148cd4efcac5eadd19b0a816bace Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 11:41:56 +0200 Subject: [PATCH 0953/1590] Fix a broken test --- tests/testapp/settings.py | 2 +- tests/testapp/tests/test_page.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index cea66cb3a..4d648b779 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -27,7 +27,7 @@ 'testapp', ] -MEDIA_ROOT = '/media/' +MEDIA_URL = '/media/' STATIC_URL = '/static/' BASEDIR = os.path.dirname(__file__) MEDIA_ROOT = os.path.join(BASEDIR, 'media/') diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index eab8b59f8..5a40a1edb 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -489,7 +489,7 @@ def test_10_mediafile_and_imagecontent(self): self.assertTrue('somefile.jpg' in page.content.main[2].render()) self.assertTrue(re.search( - '<a .*href="somefile\.jpg">.*thetitle.*</a>', + '<a .*href="/media/somefile\.jpg">.*thetitle.*</a>', page.content.main[3].render(), re.MULTILINE + re.DOTALL) is not None) @@ -510,7 +510,7 @@ def test_10_mediafile_and_imagecontent(self): (field.upload_to, field.storage, field.generate_filename) = old mediafile = MediaFile.objects.get(pk=1) - self.assertEqual(mediafile.file.url, 'somefile.jpg') + self.assertEqual(mediafile.file.url, '/media/somefile.jpg') def test_11_translations(self): self.create_default_page_set() From d96a4b4274e82279c2b31032d9c26bd2cbbbffe7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 11:49:59 +0200 Subject: [PATCH 0954/1590] Update dependencies where appropriate --- tests/tox.ini | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/tox.ini b/tests/tox.ini index ef0302ed7..b820b3e7c 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -27,7 +27,7 @@ basepython = python2.6 deps = django==1.4.7 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -37,7 +37,7 @@ basepython = python2.7 deps = django==1.4.7 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -47,7 +47,7 @@ basepython = python2.6 deps = django==1.5.3 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -57,7 +57,7 @@ basepython = python2.7 deps = django==1.5.3 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -67,7 +67,7 @@ basepython = python2.6 deps = Django==1.6.0 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -77,7 +77,7 @@ basepython = python2.7 deps = Django==1.6.0 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -85,9 +85,9 @@ deps = [testenv:py27-1.7.X] basepython = python2.7 deps = - --editable=git+git://github.com/django/django.git@master#egg=django-dev + https://github.com/django/django/zipball/stable/1.7.x --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 @@ -97,7 +97,7 @@ basepython = python3.2 deps = Django==1.5.4 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 @@ -107,7 +107,7 @@ basepython = python3.2 deps = Django==1.6.0 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 @@ -115,9 +115,9 @@ deps = [testenv:py32-1.7.X] basepython = python3.2 deps = - --editable=git+git://github.com/django/django.git@master#egg=django-dev + https://github.com/django/django/zipball/stable/1.7.x --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 @@ -127,7 +127,7 @@ basepython = python3.3 deps = Django==1.5.4 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 @@ -137,7 +137,7 @@ basepython = python3.3 deps = Django==1.6.0 django-mptt==0.6.0 - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 @@ -145,9 +145,9 @@ deps = [testenv:py33-1.7.X] basepython = python3.3 deps = - --editable=git+git://github.com/django/django.git@master#egg=django-dev + https://github.com/django/django/zipball/stable/1.7.x --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev - Pillow==2.2.1 + Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 From 2fa56e27bfd1b99252e5b12401e1ec9ea4805140 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 12:04:17 +0200 Subject: [PATCH 0955/1590] Move models into the models module --- tests/testapp/models.py | 17 +++++++++++++++++ tests/testapp/tests/test_cms.py | 3 ++- tests/testapp/tests/test_stuff.py | 18 +----------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 25b67c7b1..cd6c2713c 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -6,6 +6,7 @@ from django.utils.text import capfirst from django.utils.translation import ugettext_lazy as _ +from feincms.models import Base from feincms.module.blog.models import Entry, EntryAdmin from feincms.module.page.models import Page from feincms.content.raw.models import RawContent @@ -145,3 +146,19 @@ def __str__(self): str('categories'), models.ManyToManyField(Category, blank=True, null=True)) EntryAdmin.list_filter += ('categories',) + + +class ExampleCMSBase(Base): + pass + +ExampleCMSBase.register_regions( + ('region', 'region title'), + ('region2', 'region2 title')) + + +class ExampleCMSBase2(Base): + pass + +ExampleCMSBase2.register_regions( + ('region', 'region title'), + ('region2', 'region2 title')) diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 1b6ae0f03..be50922e1 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -16,7 +16,8 @@ from feincms.content.richtext.models import RichTextContent from feincms.content.video.models import VideoContent -from .test_stuff import ExampleCMSBase, Empty, ExampleCMSBase2 +from testapp.models import ExampleCMSBase, ExampleCMSBase2 +from .test_stuff import Empty # ------------------------------------------------------------------------ diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index ad2283065..8babb3e81 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -11,7 +11,7 @@ from django.utils.encoding import force_text import feincms -from feincms.models import Region, Template, Base +from feincms.models import Region, Template from feincms.module.blog.models import Entry from feincms.utils import collect_dict_values, get_object, shorten_string @@ -86,22 +86,6 @@ def test_shorten_string(self): self.assertEqual(len(string), 10) -class ExampleCMSBase(Base): - pass - -ExampleCMSBase.register_regions( - ('region', 'region title'), - ('region2', 'region2 title')) - - -class ExampleCMSBase2(Base): - pass - -ExampleCMSBase2.register_regions( - ('region', 'region title'), - ('region2', 'region2 title')) - - class BlogTestCase(TestCase): def setUp(self): u = User( From 69a7bef427e77525b7cf888c7230beab05452d55 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 12:05:39 +0200 Subject: [PATCH 0956/1590] Now, the example CMS bases live in testapp --- tests/testapp/tests/test_cms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index be50922e1..52ff2adb4 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -137,7 +137,7 @@ def render_region(self): def test_08_creating_two_content_types_in_same_application(self): ExampleCMSBase.create_content_type(RawContent) ct = ExampleCMSBase.content_type_for(RawContent) - self.assertEqual(ct._meta.db_table, 'tests_examplecmsbase_rawcontent') + self.assertEqual(ct._meta.db_table, 'testapp_examplecmsbase_rawcontent') ExampleCMSBase2.create_content_type( RawContent, @@ -145,7 +145,7 @@ def test_08_creating_two_content_types_in_same_application(self): ct2 = ExampleCMSBase2.content_type_for(RawContent) self.assertEqual( ct2._meta.db_table, - 'tests_examplecmsbase2_rawcontent2') + 'testapp_examplecmsbase2_rawcontent2') def test_09_related_objects_cache(self): """ From 250f7967969476f9a6aad6d0371bd49a21e1b729 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 12:14:59 +0200 Subject: [PATCH 0957/1590] Deactivate some code which tests for name clashes with Django 1.7 --- feincms/models.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 9e78815cb..f56bc6ab8 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -12,6 +12,7 @@ import operator import warnings +import django from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured from django.db import connections, models @@ -661,24 +662,29 @@ def create_content_type(cls, model, regions=None, class_name=None, # everything ok pass - # Next name clash test. Happens when the same content type is - # created for two Base subclasses living in the same Django - # application (github issues #73 and #150) - try: - other_model = get_model(cls._meta.app_label, class_name) - if other_model is None: - # Django 1.6 and earlier - raise LookupError - except LookupError: - pass - else: - warnings.warn( - 'It seems that the content type %s exists twice in %s.' - ' Use the class_name argument to create_content_type to' - ' avoid this error.' % ( - model.__name__, - cls._meta.app_label), - RuntimeWarning) + if django.VERSION < (1, 7): + # Next name clash test. Happens when the same content type is + # created for two Base subclasses living in the same Django + # application (github issues #73 and #150) + # + # FIXME This code does not work with Django 1.7, because + # get_model depends on the app cache which is not ready at + # this time yet. + try: + other_model = get_model(cls._meta.app_label, class_name) + if other_model is None: + # Django 1.6 and earlier + raise LookupError + except LookupError: + pass + else: + warnings.warn( + 'It seems that the content type %s exists twice in %s.' + ' Use the class_name argument to create_content_type' + ' to avoid this error.' % ( + model.__name__, + cls._meta.app_label), + RuntimeWarning) if not model._meta.abstract: raise ImproperlyConfigured( From 8f431053c5372e7bd02fea29ac5916ba7ccdde89 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Thu, 8 May 2014 13:46:27 +0200 Subject: [PATCH 0958/1590] Update jquery to 1.11.1 --- feincms/static/feincms/jquery-1.11.0.min.js | 4 ---- feincms/static/feincms/jquery-1.11.1.min.js | 4 ++++ feincms/templates/admin/feincms/load-jquery.include | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 feincms/static/feincms/jquery-1.11.0.min.js create mode 100644 feincms/static/feincms/jquery-1.11.1.min.js diff --git a/feincms/static/feincms/jquery-1.11.0.min.js b/feincms/static/feincms/jquery-1.11.0.min.js deleted file mode 100644 index 73f33fb3a..000000000 --- a/feincms/static/feincms/jquery-1.11.0.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f -}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},W=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a>",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=$.test(e)?this.mouseHooks:Z.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||z),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||z,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==db()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===db()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=z.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===L&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&(a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault())?bb:cb):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:cb,isPropagationStopped:cb,isImmediatePropagationStopped:cb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=bb,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=bb,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submitBubbles||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?b.form:void 0;c&&!n._data(c,"submitBubbles")&&(n.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),n._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.changeBubbles||(n.event.special.change={setup:function(){return Y.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),n.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),n.event.simulate("change",this,a,!0)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;Y.test(b.nodeName)&&!n._data(b,"changeBubbles")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a,!0)}),n._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!Y.test(this.nodeName)}}),l.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=cb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return n().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=cb),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});function eb(a){var b=fb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var fb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gb=/ jQuery\d+="(?:null|\d+)"/g,hb=new RegExp("<(?:"+fb+")[\\s/>]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/<tbody/i,mb=/<|&#?\w+;/,nb=/<(?:script|style|link)/i,ob=/checked\s*(?:[^=]|=\s*.checked.)/i,pb=/^$|\/(?:java|ecma)script/i,qb=/^true\/(.*)/,rb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,sb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1></$2>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?"<table>"!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Db[0].contentWindow||Db[0].contentDocument).document,b.write(),b.close(),c=Fb(a,b),Db.detach()),Eb[a]=c),c}!function(){var a,b,c=z.createElement("div"),d="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";c.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],a.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(a.style.opacity),l.cssFloat=!!a.style.cssFloat,c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===c.style.backgroundClip,a=c=null,l.shrinkWrapBlocks=function(){var a,c,e,f;if(null==b){if(a=z.getElementsByTagName("body")[0],!a)return;f="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",c=z.createElement("div"),e=z.createElement("div"),a.appendChild(c).appendChild(e),b=!1,typeof e.style.zoom!==L&&(e.style.cssText=d+";width:1px;padding:1px;zoom:1",e.innerHTML="<div></div>",e.firstChild.style.width="5px",b=3!==e.offsetWidth),a.removeChild(c),a=c=e=null}return b}}();var Hb=/^margin/,Ib=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Jb,Kb,Lb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Jb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),Ib.test(g)&&Hb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):z.documentElement.currentStyle&&(Jb=function(a){return a.currentStyle},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ib.test(g)&&!Lb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Mb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h=z.createElement("div"),i="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",j="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";h.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",b=h.getElementsByTagName("a")[0],b.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(b.style.opacity),l.cssFloat=!!b.style.cssFloat,h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,b=h=null,n.extend(l,{reliableHiddenOffsets:function(){if(null!=c)return c;var a,b,d,e=z.createElement("div"),f=z.getElementsByTagName("body")[0];if(f)return e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=z.createElement("div"),a.style.cssText=i,f.appendChild(a).appendChild(e),e.innerHTML="<table><tr><td></td><td>t</td></tr></table>",b=e.getElementsByTagName("td"),b[0].style.cssText="padding:0;margin:0;border:0;display:none",d=0===b[0].offsetHeight,b[0].style.display="",b[1].style.display="none",c=d&&0===b[0].offsetHeight,f.removeChild(a),e=f=null,c},boxSizing:function(){return null==d&&k(),d},boxSizingReliable:function(){return null==e&&k(),e},pixelPosition:function(){return null==f&&k(),f},reliableMarginRight:function(){var b,c,d,e;if(null==g&&a.getComputedStyle){if(b=z.getElementsByTagName("body")[0],!b)return;c=z.createElement("div"),d=z.createElement("div"),c.style.cssText=i,b.appendChild(c).appendChild(d),e=d.appendChild(z.createElement("div")),e.style.cssText=d.style.cssText=j,e.style.marginRight=e.style.width="0",d.style.width="1px",g=!parseFloat((a.getComputedStyle(e,null)||{}).marginRight),b.removeChild(c)}return g}});function k(){var b,c,h=z.getElementsByTagName("body")[0];h&&(b=z.createElement("div"),c=z.createElement("div"),b.style.cssText=i,h.appendChild(b).appendChild(c),c.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;display:block;padding:1px;border:1px;width:4px;margin-top:1%;top:1%",n.swap(h,null!=h.style.zoom?{zoom:1}:{},function(){d=4===c.offsetWidth}),e=!0,f=!1,g=!0,a.getComputedStyle&&(f="1%"!==(a.getComputedStyle(c,null)||{}).top,e="4px"===(a.getComputedStyle(c,null)||{width:"4px"}).width),h.removeChild(b),c=h=null)}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Nb=/alpha\([^)]*\)/i,Ob=/opacity\s*=\s*([^)]*)/,Pb=/^(none|table(?!-c[ea]).+)/,Qb=new RegExp("^("+T+")(.*)$","i"),Rb=new RegExp("^([+-])=("+T+")","i"),Sb={position:"absolute",visibility:"hidden",display:"block"},Tb={letterSpacing:0,fontWeight:400},Ub=["Webkit","O","Moz","ms"];function Vb(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ub.length;while(e--)if(b=Ub[e]+c,b in a)return b;return d}function Wb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=n._data(d,"olddisplay",Gb(d.nodeName)))):f[g]||(e=V(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Xb(a,b,c){var d=Qb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Yb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Zb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Jb(a),g=l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Kb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ib.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Yb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Kb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=Vb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Rb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]="",i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Vb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Kb(a,b,d)),"normal"===f&&b in Tb&&(f=Tb[b]),""===c||c?(e=parseFloat(f),c===!0||n.isNumeric(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&Pb.test(n.css(a,"display"))?n.swap(a,Sb,function(){return Zb(a,b,d)}):Zb(a,b,d):void 0},set:function(a,c,d){var e=d&&Jb(a);return Xb(a,c,d?Yb(a,b,d,l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Ob.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Nb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Nb.test(f)?f.replace(Nb,e):f+" "+e)}}),n.cssHooks.marginRight=Mb(l.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},Kb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Hb.test(a)||(n.cssHooks[a+b].set=Xb)}),n.fn.extend({css:function(a,b){return W(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Jb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b) -},a,b,arguments.length>1)},show:function(){return Wb(this,!0)},hide:function(){return Wb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function $b(a,b,c,d,e){return new $b.prototype.init(a,b,c,d,e)}n.Tween=$b,$b.prototype={constructor:$b,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=$b.propHooks[this.prop];return a&&a.get?a.get(this):$b.propHooks._default.get(this)},run:function(a){var b,c=$b.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):$b.propHooks._default.set(this),this}},$b.prototype.init.prototype=$b.prototype,$b.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},$b.propHooks.scrollTop=$b.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=$b.prototype.init,n.fx.step={};var _b,ac,bc=/^(?:toggle|show|hide)$/,cc=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),dc=/queueHooks$/,ec=[jc],fc={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=cc.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&cc.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function gc(){return setTimeout(function(){_b=void 0}),_b=n.now()}function hc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=U[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function ic(a,b,c){for(var d,e=(fc[b]||[]).concat(fc["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function jc(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&V(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k=Gb(a.nodeName),"none"===j&&(j=k),"inline"===j&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==k?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],bc.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}if(!n.isEmptyObject(o)){r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=ic(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function kc(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function lc(a,b,c){var d,e,f=0,g=ec.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=_b||gc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:_b||gc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(kc(k,j.opts.specialEasing);g>f;f++)if(d=ec[f].call(j,a,k,j.opts))return d;return n.map(k,ic,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(lc,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],fc[c]=fc[c]||[],fc[c].unshift(b)},prefilter:function(a,b){b?ec.unshift(a):ec.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=lc(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&dc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(hc(b,!0),a,d,e)}}),n.each({slideDown:hc("show"),slideUp:hc("hide"),slideToggle:hc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(_b=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),_b=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ac||(ac=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(ac),ac=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e=z.createElement("div");e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=e.getElementsByTagName("a")[0],c=z.createElement("select"),d=c.appendChild(z.createElement("option")),b=e.getElementsByTagName("input")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==e.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=d.selected,l.enctype=!!z.createElement("form").enctype,c.disabled=!0,l.optDisabled=!d.disabled,b=z.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value,a=b=c=d=e=null}();var mc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(mc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.text(a)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var nc,oc,pc=n.expr.attrHandle,qc=/^(?:checked|selected)$/i,rc=l.getSetAttribute,sc=l.input;n.fn.extend({attr:function(a,b){return W(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===L?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?oc:nc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(F);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?sc&&rc||!qc.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(rc?c:d)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),oc={set:function(a,b,c){return b===!1?n.removeAttr(a,c):sc&&rc||!qc.test(c)?a.setAttribute(!rc&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=pc[b]||n.find.attr;pc[b]=sc&&rc||!qc.test(b)?function(a,b,d){var e,f;return d||(f=pc[b],pc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,pc[b]=f),e}:function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),sc&&rc||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):nc&&nc.set(a,b,c)}}),rc||(nc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},pc.id=pc.name=pc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:nc.set},n.attrHooks.contenteditable={set:function(a,b,c){nc.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var tc=/^(?:input|select|textarea|button|object)$/i,uc=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return W(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):tc.test(a.nodeName)||uc.test(a.nodeName)&&a.href?0:-1}}}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var vc=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(F)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===L||"boolean"===c)&&(this.className&&n._data(this,"__className__",this.className),this.className=this.className||a===!1?"":n._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(vc," ").indexOf(b)>=0)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var wc=n.now(),xc=/\?/,yc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(yc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var zc,Ac,Bc=/#.*$/,Cc=/([?&])_=[^&]*/,Dc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ec=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Fc=/^(?:GET|HEAD)$/,Gc=/^\/\//,Hc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ic={},Jc={},Kc="*/".concat("*");try{Ac=location.href}catch(Lc){Ac=z.createElement("a"),Ac.href="",Ac=Ac.href}zc=Hc.exec(Ac.toLowerCase())||[];function Mc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(F)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nc(a,b,c,d){var e={},f=a===Jc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Oc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Pc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Qc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ac,type:"GET",isLocal:Ec.test(zc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Oc(Oc(a,n.ajaxSettings),b):Oc(n.ajaxSettings,a)},ajaxPrefilter:Mc(Ic),ajaxTransport:Mc(Jc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Dc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||Ac)+"").replace(Bc,"").replace(Gc,zc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(F)||[""],null==k.crossDomain&&(c=Hc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===zc[1]&&c[2]===zc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(zc[3]||("http:"===zc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),Nc(Ic,k,b,v),2===t)return v;h=k.global,h&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Fc.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(xc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Cc.test(e)?e.replace(Cc,"$1_="+wc++):e+(xc.test(e)?"&":"?")+"_="+wc++)),k.ifModified&&(n.lastModified[e]&&v.setRequestHeader("If-Modified-Since",n.lastModified[e]),n.etag[e]&&v.setRequestHeader("If-None-Match",n.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Kc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Nc(Jc,k,b,v)){v.readyState=1,h&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Pc(k,v,c)),u=Qc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(n.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!l.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||n.css(a,"display"))},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var Rc=/%20/g,Sc=/\[\]$/,Tc=/\r?\n/g,Uc=/^(?:submit|button|image|reset|file)$/i,Vc=/^(?:input|select|textarea|keygen)/i;function Wc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Sc.test(a)?d(a,e):Wc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Wc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Wc(c,a[c],b,e);return d.join("&").replace(Rc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Vc.test(this.nodeName)&&!Uc.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Tc,"\r\n")}}):{name:b.name,value:c.replace(Tc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&$c()||_c()}:$c;var Xc=0,Yc={},Zc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Yc)Yc[a](void 0,!0)}),l.cors=!!Zc&&"withCredentials"in Zc,Zc=l.ajax=!!Zc,Zc&&n.ajaxTransport(function(a){if(!a.crossDomain||l.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Xc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Yc[g],b=void 0,f.onreadystatechange=n.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Yc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function $c(){try{return new a.XMLHttpRequest}catch(b){}}function _c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=z.head||n("head")[0]||z.documentElement;return{send:function(d,e){b=z.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var ad=[],bd=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=ad.pop()||n.expando+"_"+wc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(bd.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&bd.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(bd,"$1"+e):b.jsonp!==!1&&(b.url+=(xc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,ad.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||z;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var cd=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&cd)return cd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h,a.length),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&n.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n}); diff --git a/feincms/static/feincms/jquery-1.11.1.min.js b/feincms/static/feincms/jquery-1.11.1.min.js new file mode 100644 index 000000000..ab28a2472 --- /dev/null +++ b/feincms/static/feincms/jquery-1.11.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px") +},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m}); diff --git a/feincms/templates/admin/feincms/load-jquery.include b/feincms/templates/admin/feincms/load-jquery.include index ac93171b0..8200d5465 100644 --- a/feincms/templates/admin/feincms/load-jquery.include +++ b/feincms/templates/admin/feincms/load-jquery.include @@ -4,7 +4,7 @@ Include jquery, override this template if you want to use a cdn version or load more plugins or whatnot {% endcomment %} -<script type="text/javascript" src="{% static 'feincms/jquery-1.11.0.min.js' %}"></script> +<script type="text/javascript" src="{% static 'feincms/jquery-1.11.1.min.js' %}"></script> <script type="text/javascript" src="{% static 'feincms/jquery-ui-1.10.3.custom.min.js' %}"></script> <script type="text/javascript"> From 29cea07884859d2c35437fa05725c4241fba9ad4 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Thu, 8 May 2014 13:51:39 +0200 Subject: [PATCH 0959/1590] Remove leftover jquery 1.9.1 --- feincms/static/feincms/jquery-1.9.1.min.js | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 feincms/static/feincms/jquery-1.9.1.min.js diff --git a/feincms/static/feincms/jquery-1.9.1.min.js b/feincms/static/feincms/jquery-1.9.1.min.js deleted file mode 100644 index 006e95310..000000000 --- a/feincms/static/feincms/jquery-1.9.1.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license -//@ sourceMappingURL=jquery.min.map -*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; -return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) -}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window); \ No newline at end of file From 641216197c58ea6e3b109cb88db95b026782b8ef Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 8 May 2014 14:31:35 +0200 Subject: [PATCH 0960/1590] Fix two small flake8 violations --- feincms/models.py | 1 - tests/testapp/tests/test_cms.py | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index f56bc6ab8..c923b209f 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -17,7 +17,6 @@ from django.core.exceptions import ImproperlyConfigured from django.db import connections, models from django.db.models import Q -from django.db.models.fields import FieldDoesNotExist from django.db.models.loading import get_model from django.forms.widgets import Media from django.template.loader import render_to_string diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 52ff2adb4..167d690c9 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -137,7 +137,9 @@ def render_region(self): def test_08_creating_two_content_types_in_same_application(self): ExampleCMSBase.create_content_type(RawContent) ct = ExampleCMSBase.content_type_for(RawContent) - self.assertEqual(ct._meta.db_table, 'testapp_examplecmsbase_rawcontent') + self.assertEqual( + ct._meta.db_table, + 'testapp_examplecmsbase_rawcontent') ExampleCMSBase2.create_content_type( RawContent, From 2019e3c0d495ff70a4f1f70839a5cbbd274cc785 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 14 May 2014 19:55:53 +0200 Subject: [PATCH 0961/1590] Django 1.7 is not supported by FeinCMS 1.8 and 1.9 --- docs/releases/1.8.rst | 2 +- docs/releases/1.9.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/releases/1.8.rst b/docs/releases/1.8.rst index c02d7edf3..d8867277b 100644 --- a/docs/releases/1.8.rst +++ b/docs/releases/1.8.rst @@ -133,4 +133,4 @@ Compatibility with Django and other apps ======================================== FeinCMS 1.8 requires Django 1.4 or better. The testsuite is successfully run -against Django 1.4, 1.5, 1.6 and the upcoming 1.7. +against Django 1.4, 1.5 and 1.6. Django 1.7 is not supported. diff --git a/docs/releases/1.9.rst b/docs/releases/1.9.rst index ed0d4a2fb..b450ead3b 100644 --- a/docs/releases/1.9.rst +++ b/docs/releases/1.9.rst @@ -83,5 +83,5 @@ Bugfixes Compatibility with Django and other apps ======================================== -FeinCMS 1.8 requires Django 1.4 or better. The testsuite is successfully run -against Django 1.4, 1.5, 1.6 and the upcoming 1.7. +FeinCMS 1.9 requires Django 1.4 or better. The testsuite is successfully run +against Django 1.4, 1.5 and 1.6. Django 1.7 is not supported. From 7388952508061d9f2d805fd5acea1bc0542420aa Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 14 May 2014 20:03:30 +0200 Subject: [PATCH 0962/1590] Initial version of the 1.10 release notes --- docs/index.rst | 1 + docs/releases/1.10.rst | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 docs/releases/1.10.rst diff --git a/docs/index.rst b/docs/index.rst index 8de27dde6..5c70ef46c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -76,6 +76,7 @@ Releases releases/1.7 releases/1.8 releases/1.9 + releases/1.10 Indices and tables diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst new file mode 100644 index 000000000..1ca75f270 --- /dev/null +++ b/docs/releases/1.10.rst @@ -0,0 +1,53 @@ +========================== +FeinCMS 1.10 release notes +========================== + +Welcome to FeinCMS 1.10! + + +Full compatibility with the app-loading refactor in Django 1.7 +============================================================== + +FeinCMS 1.10 is compatible with Django 1.7. It shouldn't even be necessary +to change your FeinCMS-using code. + +The only change is that we cannot test for name clashes in content types +anymore. This only concerns you if you were using more than one +``feincms.models.Base`` subclass inside the same app using the same content +types. You should be using the ``class_name`` argument to +``create_content_type`` already anyway. The technical reason for this change +is that the name clash test requires the app registry to be ready (which it +isn't yet when creating content types). + + +Backwards-incompatible changes +============================== + + +Removal of deprecated features +------------------------------ + +* + + +New deprecations +================ + + + +Notable features and improvements +================================= + +* The bundled versions of jQuery and jQuery UI have been updated to 1.11.1 + and 1.10.3 respectively. + + +Bugfixes +======== + + +Compatibility with Django and other apps +======================================== + +FeinCMS 1.10 requires Django 1.4 or better. The testsuite is successfully run +against Django 1.4, 1.5, 1.6 and the upcoming 1.7. From 1306a0ec44ad0499f82b2821d30cab3f179a1399 Mon Sep 17 00:00:00 2001 From: Denis Popov <akadan47@gmail.com> Date: Fri, 23 May 2014 06:57:08 +0400 Subject: [PATCH 0963/1590] Update Russian translation --- feincms/locale/ru/LC_MESSAGES/django.mo | Bin 8568 -> 19648 bytes feincms/locale/ru/LC_MESSAGES/django.po | 709 +++++++++++++----------- 2 files changed, 374 insertions(+), 335 deletions(-) diff --git a/feincms/locale/ru/LC_MESSAGES/django.mo b/feincms/locale/ru/LC_MESSAGES/django.mo index 12c27af3bfe277c3838077efcbb144cdd2f44110..c853de1cba925b90d5dc206e0f062deeec64c668 100644 GIT binary patch literal 19648 zcmc(md6ZmLoyV^TiopdCP(kq#2_%s2bi!&wSh7KYKulU(Ayikr?k-YYRo1KO&{4+_ z_QgaQ6hy%V6*q>Eq_Zc0`-)ZSFyqnVGK=G=$8(&~8J+Rye7?VXU)8Jb1kit`$gS^N z?)}~0{q6Tw^P?jVexKv>6z!F?Z$8ht8P9R<9WT;T=MF#8xof~9z@xz$cpP{ucm()y z@I-JM_+0P@;3?pb!PkP*Uh3&C0$<F14%GN6_(JebP~$%Uz69I{9s)iIir)9Yx!^yB z=hKdI4i??v0bd5bjQiukY2caR`Gp`XxQoF>;9I~P_!00>@E{iR0`M?U^BxUq$uq!X zz|+7X@DlKN@KI3onjrt&Kl61m_y-V@?gR#%1fB_MT~~pJgV%!32j31J2HpT_+(uA* zYzMWT$3d<8E1>xL7FY-W0X!JIj75sh>p<PV349HBHK=jxLD9bzJQlngoDDt#o(}#H zJOe!9<(}V*z*lhpR#5zofr!}M07?$`1pEZ}0QXx!@wI|M>i<?yd>6xg6<ommJ3-0& zaZvmo0yA3Yi$IM(1{6OLsQF$GMqm*X-P=K%9~AvhfUxd92WtEmL9PEukbmyGd@+^# zHFzd?D8}^`@O)7HJ_u^uN5cJQ0zLw2zOA6<c>=6~Uj@bYIXJ@w;6hMzZUpuGHgEuZ zFQ|3?47?CL^;OQ@1df8U!T$thw-LtE3$6f91+NF^fe(Xu@F(D%;G$PMHw$cm;^%)s z>Ghz<^LZ$E5%))fec)B#x!?v+a`*-)IsFWjef|lQJsfp{=Q{#LcP1!5oCE6pd7$)g z33wEEHHgW%1k`$O2jy3Hfzsps0Y3>!evg3C*B(&)zaH+t6YwXX<p1mN{`cXzo9^d- zF(~;S8}QYj)_o!<dZz@O7oPWr`wKwvbulQuR)V7QR#5Zh0<I3&07ds*pyY5<xW6;p z-vw$N9{@G}p@5HqqQ4u|dcO#2o))P2p9=U>P;&bfC_OwE=ahVp0~H5O21WmDP;qk! zC^~NhCHJeq=Ylm*bjLu=dp)RmZwJ-?p78!dpw{ycsP#Mys{d9{^!A45-vKrM_rvpF zfLh<5LD7A|iJs46K;2Id_j5qeJqJ|(1)%u443u8p0BXKf;KATXcs>fsz8c~AjiCD7 z28xfnK&}75@O}c+I(C5?_c$m%z8&8G5Il(cpMvW5FQEAN1t|W02a4Vw!Jj_|8Z(?* z%l&_!<n>TH+56q?;3+)c1}+4D3W}c@Go3pNJQKVUEQ9=WU*b!C`fE^rcET*@a7lMH zcm?=3AXB&}LGklDQ2c0;<-qenJ%1y3Fqj85-w1dSI1Umz+!LVI`y){C;+NpV;HwB0 z4}jkQm3OY4?fvwfAfd&*7Zklmz_Y=}!S8~902hJZ>hb-KB>0H`KJc~RD9F;?L!kKl zHprANn&a1ZDfnXUSA(*nwcuO8jiC7WCHO+{PvD{8VSU~{jskzi{qdmQAHrfp=SWcZ zCx8QBFDO5`0hHYD16iW`4tO>ACvZJ@6~fPhKLN$>qSNqoumncn1gLROfiD3MI^FYs zB=~3U=YgawH;<%u6nH6kICu?+s@&Vab>IgBzVb}p|9)^9&$of%`w39%e-f15PJwC3 zvj!dwJ_5=vz65H${|bu!Z$a^QJj#*WE&&y%uL3UsuLBcsC%6;rK{@L8Zy>Je{s$Dj z<NLjwdq70)&IHwO2>dT_9DF%gJ;%A5!P`Lbe>hA^F2{izz*E6>;4ZKVo-^OM--Dk6 z<qw}Y&)dVlgKyxz|9o;Yco%pL_;c{H;L;1co__~Q9zVR$^K;??Kkr%Ki9BBb-UAMU z%fLT_*MiHK43)VZAgXr10_8`?W3*cDVo-V-2pEUwW1#eS6G#ei_XXSozJ~iBff|3% zV$aVJ0Z#;v;rUsh=D9pz0~EavfzsEbp!E3zQ1kx=l>QG|;_Hi-fO<X)l->7($ASyN zL%^%U`vRzOjezSx@wE}ud=G%q-xg4Gz6?$WzYV?&{15O5a2mpu9$yKH-pQcmKRw`L zQ2bsAz7i~f8h0Bgx*r5j20spJ{5Qk>_raHP{~Vm@MDS>ECfE;(ULMpu<KS`N?Eyat zK9Bp)gQEL2Q2hM{R6P14sP!GY)URg_C^{=Z=_eoVZwYuWD7*bMh^f2Jhx<Q*qIdKq zzRo!fRKG&NcY<2y`vZOo6yLi*$+-#60)Gt3|6XvZU;h~a7l87ME5Jj+Rp9Huk#N5Y zl)SzGiti>k1N<#G4LtTTufG|f<~tkIIxhkxpErW)w<_SZp!CxS_jiHP_x&L0%4``I za824bX~Q&3z~RQW|9AxaF70Eq^mARf_!cNx)M(ex{*E?}runr-T*6|L{8^tb(r&UV z{63&$tIvmM*U}!NZKvsTC9Oe|Jhj$O(DZqshxWJZS)UKk&ZgZ!yM^|C+6A;HX$xo( zO`o^Z*3%|*!{<g1?i=7cX>-E;N^mXh-QgaQxsh;9*m3vMZVmU_0)7PiaJVKkx>ezN zdcYJEgC>9GXCAEK`W=~j%+fyc(F#qro_=IU2@TgWo6++Xv^q^OB1hXxdlhX9?M1YW zv`^FY>7mI+6i2>F)8`To?(u+w0Y4k?p@4$-(jKLiXfaKnPttbNZllemy@$4%wu|;P znm$+1X3!3zy@ICC3ur~!nY7Q)UPrr=rq6dgSp9bl*SLgzs(gQm_IcX3?TK@54tNjv z7TU!$#hbsSrJuj&VpF&|3H%${@^Ie^K1JJ1`xLE@rq41D?tS1Hw8i26tpV48U#6W( zBV}1^*a03)OFs{Ui?4vMr;XE2rtPCWOjA6%kM>g9S+v_}`kYSNU{}5dxSQ)IXrxT{ zh4B1xaDaAixE}+z(#o{!X?fbsw8Lq~)ATuxb`|YG+HBf$Y5IJe_B^}twb4wjzfSue z?TxfkXm6tF^ETRHc16wxcZTZ}T3qa*6~coLf_Kn9N_$s$HY%JJ?dLONX1+2y8kg&< z8cAF$=SJgMNtEP@g{V@FIxmyP;ApYFs*tPm{@lS@H0Qi2<Xp61oFPNSQa!G%su$}e z(V`AdXUJC?<vNeTebVb@6e7CENmLxIR%-RQ;ASMzNG^#6<G37+R>tB&RIfz2s2s0} zs+FWzFILLE?!rPrjmb*6@^B+JtcmKiTsbM_)FY}4Mbl@@tlEp|)-@Lm){5~^6knH* zYt?#`G)6~rwc^@hc{r+%#PC$EBL$7Dj}((gV{M`+SFX^Z#$;o0ZLpHWtGtwqY<{Fz zDp+T`9gPdcTv!r(=MmR%r8aKww1i?k9<`e!F2#A)8$I2KE(${k)m>OBskOO<(PA0q zpo=7HmC+9KQE@05E{??#SEEp@xCQZ0r53vd#c~dg7Bot$qeit<$rTXqo0l#(uKV4> zTz&*vuU~N)m*sq15+H%70LS&%uVCt<*=Q`E!-VJ%nfPi!nz?#ZigO8)Eyt0Uq@>WB z(nZI$HCjNlrdS_|3dNzJ*v85*qWX9>j%McSj6i7!q|-fzMk=Mks`xtDlnvG+#Oxo< zVum38g(H|r9L-2vxDq)`C3XudrBbd6+x1$kyYf)6h7c>=%MG>>1RSGp;}COXy-Ad7 z)GMPHUOrbUjdv8%8x44VYsCT+$f^e8k=$6Z(x}aja@cQD8Eso00;yET+nR09RjCz+ zQ5kxu#c-T8bGL{GJ%hOfg;g7arD8IIIlDz(Q*9ILHr!R!QlpkD%}VH(<ZH!h>M+Go zOx`WR^QG=axe(WqdajI#R>tHd#d1=wHS*pA7Z=bojwTT}yUDnpTkM?-tcrlimTNpb zYIBt}d>nplv1%6Rmaxi3jYzP>;)q*P$|WQ2;(=wCMFYjcxW5|9m5Rh7xq7u$DKzp( zKygO#r4X&j)yi<3^hV2NdT~^X$BKBL{Jc?B3@fzdJQ$ZMYtV~)!yXpP4aW9EZZu93 zM3Nw?i_suoNnOr-F<Ns=hszovlEzzxqjY+=)FisJOkk}mg7v$l7+x?fwBN|*nPRAc z)%3bc<MB0>S^;Z<Y|*F}qQP;bkMAULu9hE(;xeWX6E`o5b7OHNpTOP}vA8MMYvWNe zQfUy7P~3QwLs#_D%J8vtklCRh$r~G1Q~)j;m1+$$fKD1$d)?(2?64O#o)(uAgzhd! znrRe|Mwx3cmO-Pn%ZYkEp};0L#d5V#H_iHJq-WK*Hd;)K&=nS1D`td=y8=Fgvmn}B zZ8)wg67@z4Vx%Q;i(tOgz@G^9$q0-SU$p$e7|}@U#A_m&e;9L#czj68MWqTJ>In|W z8*_x3d>yYOEE$n<XRV?_(o-5pPSzNfBlav*x#f$NM1@Mep~UHyTQqRXrKp8|?QVGu z%^J-_ni_1>>)5I{HWpEf^9p2ifDJAr3!i$3k%QO5Rqr#CV4Q`-XCNZecPmz|jD}+L zlU^ilMQq_J?_*;c5zmi&cDF2Jue?QS8HL_-P$n6i&ojRm|4@zyXW2x#0^P7aGdg-J z@cNu7CY0m>Tg=pvMXY`RyK^g<->uBLK_sggEv_}&<dqU?JL6i_P_33YL<w(9lL#Es z2u^~{5;DaL@uwEp3UxqlI!v}TN`xU75oyMX1({fC81gNzLs6HhjaM3YIwVnYzCpZz zK_4YLwk6u-f?GL4Jj^%hiLTbTm5QV*>y>JxaLO!hrPW+OCro%J%Y?d46xED`KxC_m zV;1K6EC*tylSdBZhViChH_&!LTWLGbA+16Y8^(7`0FsT58>{1S*>Nt^Po}y7%xE>g zIt(Dnw9J~4-m-bEQvv2H)uI=s^gswDzve9udIRb;qU3B`uS956Ha3mr6wg$F&bIp@ z(tKr&RHt6Sq8o$O14)UqPM3~MRaQ`KrNK>t67_ZtOQqd!6l!?<P%$R_!bO^A5?MA; z2UFF&Q6V?p8(kO$uM1Jv`0#U8$}Euy$BIdD5TnCyH06jY1v9do3PF2T#xKmN!(>_q zGZU+<C@CSQ!Z=}cHKjC(Bv(!|g6KSBXJ4v?9FiHKwW;9nrXNScahV0mi#isLpekX4 zv^%03Y^YY&YQ$of>v+y>eT52gQUyYEA~RF^QIRUn%C0))cH)P0T$%7*EU%V|a`M7@ z10iCZW5~V2cOkCKj*7i;Z+|pWuUGr$%vrN$O>gMfOUjzFCRfjooIf^y?dY|0Yt^-j zR=l~-&rz40Sx2FmP&AIS(x8-(l?nBY60TrEik4bmJX(tPrBqg2D;Hl8u~Au#Em9wf za;ZXXDvhF`xu^HZG-`;Qq+r%uYm{YX#9q_x8q4qA2UuyTLcj=CG*UznlnLW*K$f4l zE46CAN!D;|rP>>UJtt(=wmVxMs8H-%_@a(QjA-eaP*cW*YhWtQuO6&i7v%<t*S+pd z#JNJnmPbX4X|_|kG(f;C4q<vSN1x8Zfbz+8oSXilUyfD&sM_d^wqQhXQU2}>PPZrQ z-mHim%CR>nP@^So(kqlhFb~iDrZUR*rplCvsEeFTyHZXJb*o)#8A(Udx66?{DCpHC zdz}Wb{XK)!7>woQwwY=;arvCpH=qS)%B}Qr+@-}57iBCRhpyB{yKd<0_a7<xz}C5A zi=;l)adrwLbr<5JN9A1=yspqG_FbW}rtBnS7mvcQi_7A<0M^+fCx+uL?3BS!^(Ag7 zt<AMJbGAV%mWL|-Dk0PPD{b2BiV>_PS9gAIVc&_vTsxtHyRd(C=-Y=ImsX!#5ZFT~ zb@FdFn!B#oHlc~@#OcgsR`LgUoE@p_I#D?z9eY3?vufO#DF;LFlGN_sbryh4rd2Wd z$tiM~-{c+DJUesJs7gI6Yl(YKQNq508g-xWKs!p89&xy8E$-n71hD8-|ADRtUy_?{ zvkz4Ab{<k87o5G;6;Z&|a;n_ztRs7!xHP5Xzg$~YR#Ww5-q5~ETteEHQv~EesWI%R zh*Y(@WPDU=VlG=}JvW@Vw6ttrv>8a>qz}{=-?Mb+GA=~u&)(8a7S^abi|hW|!oR;v z0G~ar%;?dQme(p`uxDwZ=Sp91_eV?OVtL`RmD5(liYh(JlHp>ZXF+2)=^3c>N7I&H zG0<b1ZkF4#2q)@~=Jm}zy{GSto_X`Q>_6iSuKW7v*h2x!l-Yi#^~~+-nRiCi_uBrs zXPnx{XWC_0bI(9HrmEEXqh(~bks<->(wI85JW?sGjm{lieZdfnjl{)zZ+_%FM)@PI zo`E<w+8?cGuyZ0+%*>=Q6IF32zRnUEb*h${%&E>1q5NnvCv~VfwZ@!TZHoO-tubxc z(q)S~BAMIUH*KLekDdX9+;94yL*6Tv&#}}*=9vHbfh9d>clv2X9NP3OF6RmS+B}~< zSgcQ5ZU+rLO9%l;e^mD84$1t}&WZfx{F&t$bNlAcpBtTYQl!hi6XwsI8=W8ZMRe!> zy!rFeSLe<@U6(eZ@7%e4(L3JZhtQ{Q7GvfzX5OrGrcFNOY<{@8uerN*XLCEaxw)ye zzB!?LtD&bHe73G{?rLtL@22MNXlCc+67%jHf6hAK`KKm>FoBU=@^mMl%(Ab!hyNy; zd*NtPYh7~(*PHD`v~?rX?`-ZC!x7K-G#_j3YptW-4*J<DntPl3T=PK~WicFeCex$l zqpdr*rtbv3CPce+o9IV$-lQ*$+}E6l?A7&<+t=%wck}2`=GzSM^{qRnJYYGg@ytp( z)J17)_KdYdsCB1g95r{rhQz&#CG3n?!Ftwkhw-p0G8VVDHoyyuYTeM<7$JLT8u!~^ zXs;wPl^wq-xFV)z_n4je{X!y0?Q7j)<o32Uv^GFr9C*sDn_D;Rhqm;wm3cSyq&jHb z5lIOcg%;J^B1JI4hN**F??z)LcBypg`{rgA|7c)fFV|iXfAxF^U<(UGkZ|IfcX5$I zw{&GwW(in^@7>(mx&c|OM@Z5{)Oxq<1HDa>+8vn8d*~`DVS!kWzGMwM5Vn@J(>3ow z$XldU?9;4D);GaKvU>R<7^M>C5dz+<Bj_GELhB|-Z*ETXyXJiix)ll?qqhmPeQ?bO zV9@-hxyd!}moyPDgJnZZ8X1$gao}LGdj8T8v!mAf-sY}e3>lYdZG^?$e78j=9&KW5 z!0f<`rnyVrw!@5h4;<~0Su##kwwg;~Q9LtYaVY~s_E}46ZbIa6YeL>`irc1<9bZ(m zdW>aWFC!(gNqw^O?Y4NYl|8Tz9|RJ3Xp4SRG}9hEhUDa^go!kKOeUH=YiEM4b9NNf z?H(Il^IoR+>hTsZBboXP<!&PQDA4V7&5ug!Fus>)V37z@Ml$Qe;~?CQUI}fiXkv=E zWH%6Gpas{6IW}{ncq=Ytr`{HKh*rh}=t6=}z$8{lgc*$z)V%qcf@IjcQB2f)$S4zf zJCfVie2lRQB(em*`ru9yKZ~?i#{6sxQ$7HPxXC=4SCZJq`pi+WfRCE<NX_EQ5*e!Y z;RvgdiDB&cmf}1@*$)*F*$3xagPpW>ZNXfAEcxu~2}FHrYR?B@$qLhb46#XTJ7h7f zn_&rkKPa;8_3kIwbw}*ZuMo`#;KPg;`qC#~%GEwpZj%!I3?DX`WD=Y2O=RiV1hKDm zCu)(uNZ5N@8(C7|+vi+m7Fb23A2CgAB2i^Bt9g({NQ9(e-c3xk+{vON7~#Spxrws8 zZ<0Ab%tY6VD|$|u@L4AZL{3oAt{2&dVCng5=N1`&YknN@U=LzUH@h*xTm6qGou5(6 z-la&HgelUZsPQgkZo<#gA5~JTM)}^pw=v55;7%kiXI0wX&HJ578Wv1i7%Pj$h{Xqb zw8}twMzL5gcI4|4g-jXPfoxY+C#SMWBe}3*sh-JM$SQIc>2A^wH<&zih{Bs{n|qBh zpTe=(`&soZ;#pbjUc89;jZ0B&yIAn%sq6N>z^V|MQEAJONBU97>t&KDhm<S<G0caD zwmEI}i5It@9M%Y5uK6&mwo44G-t0*^62?1DfF!Z*`%uLO6O?SrB7#+v(#wwQS|PK6 zc!w%1IV<DhH_{++L19g~-3LGTwJ@|<>DP3Oqla=&{ou~RgWfUe9>SYKEfyAGQz1(! zY^5rbpUFakG%SB{N013_2@f&~>PNaV85Iq@d;fh_EVL7DdwwW*ayGM(_md#=jm_=w zy^CecoRQ437(sy)iV$z?tk767A)41TcgU2m7?ZOJXmV-K`W48xD79IoE_=+xe$y+( zjn7?^N0a+~1+^ZItZ*@5Lri`^zS<n>9xtjiy<1<+CksY+M0i}`2Fn)GlL83OwNbF> z<#1xZci3+VyP3IUe##a*RfG9B>oxl*bhoCaAnj)M6pEw_Y~2c@CcNNu@L;Z^xJ(o$ z08L~J#;44Pk^7Wq6w5G6>dP?o!`KYwNg0NDS|Mh%r)Y=DpJ{aBEUS~mShZ5hP4K0K zLtD2uBinTS9a}Mrv^tkKLj5LrBT|0<Q<U#25PV4*WDP;nu+KSRm<gQCkVPH>mi9gt z5O=`=GS?JQlO)}`sm+#A2?3KD^cJmJTRp8@j^kZN!_#0Q!HJHgA4Jb?1xshl?J%!g z=L^bB|Gx};m=&rJlDt@l+(XK+-zPC(LTTnwj`1-%P|GUNskb?!$v9g@+OL;$&Wrrs zM}aP_LVbU~%WR8R%G8eLF64=JeZsbfsi-4)7BcgSl99_4gLb<M_4A>lrR+~7={RvA zBc9mL23F;W3OSsi9Ykf4SOd>g3o3|9NU6n2EM0ZifjQ`|zW9p<N&@9NtBGxWr~v`U z7rdA8Q0BsfZmLN-{fwc?O+#hJ3h!wth%|A3xmnx1Raj<r&+VWr?Q6W`qJ}54@0(0u z@~Vjv_!T5oO4&xboloQ#c!wE=?~*Mf_0|_qN^2dtdK2hoTJc(&V&YEsbUMqht}5mx zut`>_XsYg$)RV3=l>bwA)0uc@!l$NT`-8G&=X@#oNa0GsL;^jbpVGIN_69hA06}y` z9T`RXKml9PgIMeL6h3}aOJG>YLTZDsRBXkr-@IEy_A6uc%r8%!R49A0`<p&fGfJ~M zD(D=j;Ai-+1m~+3UZ=^zcvX(*{u%pe$x%N%13?Rwe-TOi;IARt{1}VfA{RD=d0#^E zuK7t`bY;%eE~HJFv3ElTwzsBaCliuHzX`(v5nCuX6xXb#k{H*?AQTxbH=<H2`=&$+ z3`P949a`C++<+nPJHZ@0*hl;5&CD-b5y`}RFittfZYK0;liXqlk3KHTa58&TY(yy< zW?)jqyA~0)puE#gf9km$occVh3S0p@cmR$Y{nNU;@ji(7gr{%ZQR!NTC%(SLtcl)M za>#)xZf`RO$Pn7$37OAM8qH}X41Cn|l^tzCs@s%(tWn)#Rox^*_I77QVS8t0>s16o z>6viYZ>di5)wDjm_yuN<m{_wvw~+Y58JbeTc1c*;L!R3Ec1~W}uJ6k(R+<_mb(d9a zP$YIKqS$Fv<du#v+57R>%eOnKDGSMDQy#>&m-b|#+X}l@BOWnUlxi7XCwErH!GsDl zi+rqK`m~*U#D(q756DY%C)#=j8lBTMY~@)IWS{7@ft<I)Rr{1ro3>rD<6zZWY(+lR zDN2U~8iKb8c1!BDDWiDr0m!2SoelD~<0F!m$%d+q$5T^?U%rkj%uhlwt9=#r;`5U9 zE`|9jxtqNDJbhgp<ZIoqi;$brB+Ind6M1$cmUNqz8q`E{AC71yD(~^XMwm@8Cz-7M zXBr`#*`I2V5tZcHg+XiG?7!p>Hrlpe9%j)_0Yjoo50o~w)hWNxrcI|GL|!kfDSKU9 z>V7Fyn-ojRbbJO4syecT??qf)>7ca{a_vBDd4SdH<YNK`^yeR_M-`E2j5$LpB61^@ zV25o>%BYgqXOY;vN0k@@$PvLJtpH%Pp!lL}(kVOp)_b7Z37rH#m5_=CD9;z4?b6(4 zrxudtn7Dm5_Ff!BwS|t{WrVy5!ONTjwhox(P_{3}OhN64qH^4nCaXznZ%jg`wS<Fc zI&#S#LZ*JVZ@TG|%3=Z$Jt#XQ$(bW4%!QiBgpOCS%qg1#?_@gTHG^sIn5-r>LK>#3 zMvR#mBPdKO{O-`)<LlA1{4y`J1DCF;7#T{!{Y}+%P-sVe>5e}2YLmFO#2l5h{|YAU z1Zkyti_7aweCuRKQcEgs4&&_vQA<(yrkh{fRKonhOxs>KL6Bki<2_X!8y!?T0h)BJ zKci88XjdBEk(HUlQLYN2yUj-YMku&?riaKreGhG+6|@xcIF7X1$J|%e?JL}^+8p@= zZ^z53aVI5S8T+J1np%Nu@(Iiihjhb!$(x3}NGHoaBojtBI)Y%@%`Di5oc(rFh?mpo zkl#YK#M14I)G<C4r2V8V`-R9!tH=#6QCV&~w$@Fab6<V=T0RpV_<coD4(IeV?N<Os znht%<CYQFYg2PyJvE7+8HHGPzJF_F(F!;Y5qGu>L5j*;Hmb?9VKGIbpZ%dyjY}++O zwp}7U>10i^mrJ&*CHhTBpe&}jTkrO!(q(8kt<L<8NMC3|Kv83zN(>uFk>SPF^(4H6 z;|xu9y0QnnL6hlv@&ncsYAMxB?bPlpG^wCgnXf`H6auQrr})VEE<I;73vG|`Ie@|4 zhvM2oVCiX=g(o)c^6*}rgDVp$_IIB}hy(STy!+CG86VN9<m4_|bXO;t*?zhmU<TO$ z=K{u8+nx@57TqyR)4k@A7=mG9@mR%FQ}L0vYbz{gwzT6#e!sdLAWI-kAM;?+o3v>< zU9?8|9k1WDnNO$&lNK_kFA|gtypuk?$7cJ;zPbkKf#z)gR7_m*>qBNL|GVO3%7~9+ zOoV01wrr<t%e8a;PAKsqV!~8_O{TxnrS?clPon^f?7R>A%FJ7q!c2SH+dR_ceg_;# z#0<{%?=WEhvy8ZaeM<oTH>s{CLHyE=@`&Xoyf{5Xv!jqMzilfrrAnFH$w65UpVHHI zGa*}<wrooOqb7EuH!7yEF4m*SM^)jCK@;GKlN78J?Q@<_3C0mY#maiA#}{^;t$wKK zQ}^ap@k)CqvPt#_a#<~6@;M_YI?DDiUY@Cs+%_YdsTMrR`zPH>M3#J%B>V|8iN|js aRWfD+l}ZYv(RrD@JWx$ez1D*SA@zTaDJ=c~ delta 3777 zcmY+Fdu&w46^94vLK0#gw!uKazP2$o*sLEI0}c=##@G%86Z0xGjn})^_QJlpdyPX> zx?m>+)rcre6BNWFC`sF-sk9^*Ok5k(rmED6=-w)=)HZ2FtEN)^plT`=r2f%<XLq2@ zXn*&c=b3ZP%)NW_wMq9jrv8|h^NOM*&;s=CSCl#r*G%O>Nk6Pq7rYD~gL#iAwFvs) zqp%Zx6?Q?Esvgrm0H@H78xFui+TVeB@KxBXR7$-~<smxmK=x2~;S4xwno_xN7Muf% zp)72Ki(wlS2jXxhJOcTtQ#^9uS;LD^9DEb<Q}6JY53j-o_E#R26?9C&niyQeLpE+R z?LBZ6?I4th&YS)>p(N=tY=GBcKD=YbCu2k$nPFI9I1e&K6~QU&ud2*IJrsj0VKsaL z*1<6J!3!_|Z$WXSZhAJdRd5UKbx_tHhcbQ&O2n@~$>1e3J_<>)x(QQ~`d?8Ik3NRj zR=1%T`n%y>)BhhR5#@3|VmJ><yU4H%%DPI!S}3Vs1!co^Q0BKmIqGdQ$iGzfnu*<p zeNZBZLUE`cilakN96bre&}&c(Ux2gV+opdE%4NI>W!;CS{}z<_zlP%2r!&aEZ1fj1 z@pCAb>7TFw=Fkua=Rw)H3`*p+P}Z%1;>ac_k+(uI++oIdoAIZiIMQv}2cgW1r>KbG zLuOzIPNsdrOc;jZ@yk#)JO^ho;SKm4?JK+zRj`Jew+Zft#qc7ObvK}_`=x1nP#pdQ zVnU^EQ`ti03n-VZiLieR!%$wg`LnaPdKp|udxPOKP~M6orhOH5(Eb=Mh2`8haijy5 zz&MmZPa9r@{8H*&o+}yn8I(x=4F_QbUkkbI??4MqpPMyU1LbJ8!<S(YN+kb+OW@Rb zN>NpHa6fE^65#hCzNtG<0?XkekSFhdAr&sRS_*66>db&rAt)*QHsm^}7onv143tR! z0QbOZK8rts&qFa>%V$*9ZGvauHYg5$W_TA$01uJQGWJ&ssfYs`pcv>d48X;-4;h|^ zvhYJFsr(%z81<QHtD@{ixlk@!5yVGTVfr^hS=VXU1yf=$LPZt~Lb9!fp}bCSK#61o zN(46zJt(RCGn94rU<I7Sfy)L<ptKvI{AYX<$|ZabioIh{_B~ll{>AVmI?CXCP};vW z{2P?Byax$V&9X=@tbx+sWq25hL#Lr+@`q54>>3mYe*vZ6HT)Bl{ySDG>+xMW#Iqc( zsvN-#D2|ju@q9Uy@g~E~kYiLGrX7KkXt$u<Xd9Asi%<mhA-UXP^erSsGLXam>S?qc z$%jUYjaFo8|9eREa*L(NnQuUHw)e|wDw1*w@dByG(E%iH#1p6#N#>-iMUtJZNcPYC zYds?s%2TKr)uT=%r6!Bam#>}r*U);?w;1j+^+wo)zG2$?p&YAZQpy@6_d~vX`w%6S zNh2S$%*Q9w#Y4_k&P&SI(Xvb}`%TX^_5VjNjVNkE%TeaiK{?|P>PB*`UC56DXev4= z@fTCsfr3a%50dwKC)$iQA}Mmg?w2@~m1q?zK`|ty1Iay+(vZc2r;nPvT?w?;^cJl* z6~QLdYTEMpEk)I+5<Q9TmvU2CC)Bxlwmy-!P+!Zd$hV^QfE9A=h}zKO*a@{E9M%sP z)adqty*g+17VXW>*DL3=<j4KdpyecNTeXIQJYo@BA1n0fPYT1Sm=%acB6ieC`qXx( z&rVpexD$#+ld7Y+#R|p({W7RJ{Jpm2gq*N#^~4fZcOo{BWbQyH8jKD2tWJN#w){ym zqx-NGw0r#hVaLb9L}q;~=~$bxJE@L@eJErPsHbedE}P%l)XRRB9f>=KRj2=utvc;! zP<8gj22`gLi(8w6Atw~=Rh|9ak&vTy+RyUn^G6RROLTFOrSpm${nw(dY2sZ{?Iy&S zF0k6>`vciPgjn^*<Ka-iFMT>u(x@+&l+H`oe#Z`~fKZ$W(o{VBI=6K0qNu++%qadR zLRc0aR_ty^lbH<lgu=EyQ2LlYiN;DRN@KxLkJ%z?DoS1yr=((upq(HH{c2gI{(afn zW;+;4*a63KVk%)rV)&N~_xGw~fA;~pl_OhcpGnZmg9L@eJxAit9EJX9kxx%AudnQL zoOn}BO>fBQ>+kk)pfx>qC>n?)A25_m_S;FlzPxbe@?~|k%j#EHb#+a3^;Na?y0`p& zU9ouIqg(ya-hR%x$x8I=ql>@L->s<Dw<~t)=#p78FS--nF?Y-zQSNCfBYMx$gSx1y zRxhYZ>x0!hb1nCZJK`O6N8I<^34Npbah>lg(ys4Z)9Y^9y+*H$j(bDipm*|1la+hP z{lGiw4a<mf&%0^wMV5?VX0YyvzFl9ghw6Vi>8!p`F-PB8{)o<Ru=2m>POxam{Rtb6 zdxI9YRi`)4(a*L`Pl@$0?<Gs7xZ`fxaxb%Wn%UPfPNaR7OFUL)`2<sCyK#5aJ7ul4 z+#Ad#R&S6QEJ(ZWV+Uu5fDJ7f5o?(R$Gu^na$jfg3d;xaWz0LN<14E5g~qx1qsF&% zdgYwum$3K3gEg5TFECj)N@JCU5;q><E*nZyuV`x4GuJH8pRX&{KVSD7y<`1b3(kDm z8F!Ska7QKYq^f7*S-q>dq#$E<G~@79$qf@m^ry}H^tR0bJ-MZF+Les&<K8g+l`V}r z*iyAnJRz_X_#!7Lxp+x=&olG7JEs4^tcESC^|>uQ`UkD0#f*~;3|v=Sg$a&sFtad| zA~&sfv?Zpp3%zN*t-Vk;w0G+d+ROF!C+FAG=U&FUQSZ2$Rx;&&(;JrN2<aYGc#`d( PaL4t$t;_VTt*!qBV=EYP diff --git a/feincms/locale/ru/LC_MESSAGES/django.po b/feincms/locale/ru/LC_MESSAGES/django.po index ab94e04a9..e10fff887 100644 --- a/feincms/locale/ru/LC_MESSAGES/django.po +++ b/feincms/locale/ru/LC_MESSAGES/django.po @@ -1,744 +1,767 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Mikhail Korobov <kmike84@gmail.com>, 2009 +# Denis Popov <akadan47@gmail.com>, 2014 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-05-22 20:55-0500\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Russian (http://www.transifex.com/projects/p/feincms/language/ru/)\n" +"Language-Team: Russian (http://www.transifex.com/projects/p/feincms/language/" +"ru/)\n" +"Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ru\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: models.py:370 content/template/models.py:59 +#: models.py:390 content/template/models.py:63 msgid "template" msgstr "шаблон" -#: models.py:510 +#: models.py:538 msgid "ordering" msgstr "сортировка" -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 +#: translations.py:282 module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 msgid "language" msgstr "язык" -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Все" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Родитель" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Категория" -#: admin/item_editor.py:159 +#: admin/item_editor.py:189 #, python-format msgid "Change %s" msgstr "Изменить %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:293 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:34 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "заголовок" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:352 admin/tree_editor.py:369 +msgid "You do not have permission to modify this object" +msgstr "У вас нет прав для изменения этого объекта" + +#: admin/tree_editor.py:486 +msgid "No permission" +msgstr "Нет прав" + +#: admin/tree_editor.py:504 #, python-format msgid "%s has been moved to a new position." msgstr "Узел \"%s\" был перемещен на новое место." -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:507 msgid "Did not understand moving instruction." msgstr "Перемещение не удалось. Непонятная команда." -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:518 msgid "actions" msgstr "действия" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." -msgstr "" +#: admin/tree_editor.py:541 +#, fuzzy, python-format +msgid "Successfully deleted %(count)d items." +msgstr "Успешно удалено %s объектов" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:554 #, python-format msgid "Delete selected %(verbose_name_plural)s" -msgstr "" +msgstr "Удалить выбранные %(verbose_name_plural)s" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" -msgstr "" +msgstr "Данные приложения" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" -msgstr "" +msgstr "Данные приложений" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "приложение" -#: content/comments/models.py:24 +#: content/comments/models.py:31 msgid "enabled" msgstr "включены" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "New comments may be added" -msgstr "" +msgstr "Новые комментарии могут быть добавлены" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:36 content/comments/models.py:37 msgid "comments" -msgstr "" +msgstr "комментарии" -#: content/comments/models.py:49 +#: content/comments/models.py:59 msgid "public" -msgstr "" +msgstr "Опубликовано" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "not public" -msgstr "" +msgstr "Не опубликовано" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "имя" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" -msgstr "" +msgstr "email" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "тема" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "содержание" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "форма обратной связи" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "формы обратной связи" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "файл" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "файлы" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "картинка" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" -msgstr "" +msgstr "alt текст" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" -msgstr "" +msgstr "Описание изображения" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "подпись" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "картинки" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "расположение" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" -msgstr "" +msgstr "формат" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" -msgstr "" +msgstr "медиа-файл" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" -msgstr "" +msgstr "медиа-файлы" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "тип" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" -msgstr "" +msgstr "HTML данные" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" -msgstr "" +msgstr "HTML данные" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" -msgstr "" +msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" -msgstr "" +msgstr "Игнорировать предупреждения при валидации HTML" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" - -#: content/richtext/models.py:84 content/section/models.py:35 +"HTML валидация вызвала %(count)d предупреждений. Пожалуйста просмотрите ниже обновленное " +"содержимое прежде чем продолжить: %(messages)s" +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "текст" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" -msgstr "" +msgstr "форматированный текст" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" -msgstr "" +msgstr "форматированные тексты" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." msgstr "" - -#: content/rss/models.py:22 +"RSS поле обновляется несколько раз в день. Изменение в названии будет видно " +"на главной странице только после следующего обновления фида" +#: content/rss/models.py:28 msgid "link" msgstr "ссылка" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" -msgstr "" +msgstr "предподготовленное содержимое" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "последнее обновление" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "макс. число элементов" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" -msgstr "" +msgstr "RSS фид" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" -msgstr "" +msgstr "RSS фиды" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" -msgstr "" +msgstr "секция" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" -msgstr "" - -#: content/table/models.py:63 -msgid "plain" -msgstr "" - -#: content/table/models.py:64 -msgid "title row" -msgstr "" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "" - -#: content/table/models.py:72 -msgid "table" -msgstr "таблица" +msgstr "секции" -#: content/table/models.py:73 -msgid "tables" -msgstr "таблицы" - -#: content/table/models.py:87 -msgid "data" -msgstr "данные" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" -msgstr "" +msgstr "содержимое шаблона" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" -msgstr "" +msgstr "содержимое шаблонов" -#: content/video/models.py:31 +#: content/video/models.py:34 msgid "video link" msgstr "ссылка на видео" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Это должно быть ссылкой на видео, размещенное на youtube или vimeo, например, http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Это должно быть ссылкой на видео, размещенное на youtube или vimeo, " +"например, http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "видео" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "видео" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" -msgstr "" +msgstr "Теггирование" -#: module/blog/models.py:28 +#: module/blog/models.py:32 msgid "published" msgstr "опубликовано" -#: module/blog/models.py:30 +#: module/blog/models.py:35 msgid "This is used for the generated navigation too." msgstr "Используется также в сгенерированно навигации." -#: module/blog/models.py:33 +#: module/blog/models.py:39 msgid "published on" msgstr "опубликовано" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Будет установлено автоматически, как только Вы отметите пункт \"опубликовано\" выше." +#: module/blog/models.py:41 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Будет установлено автоматически, как только Вы отметите пункт \"опубликовано" +"\" выше." -#: module/blog/models.py:39 +#: module/blog/models.py:47 msgid "entry" msgstr "запись" -#: module/blog/models.py:40 +#: module/blog/models.py:48 msgid "entries" msgstr "записи" -#: module/blog/extensions/tags.py:12 +#: module/blog/extensions/tags.py:17 msgid "tags" msgstr "теги" -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 msgid "translation of" -msgstr "" +msgstr "перевод" -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 msgid "Leave this empty for entries in the primary language." msgstr "Оставьте поле пустым для записей на основном языке (%s)." -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 msgid "available translations" msgstr "доступные переводы" -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "дата создания" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "дата изменения" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" -msgstr "" +msgstr "типы данных" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "дата публикации" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "дата окончания публикации" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Оставьте поле пустым, если запись должна оставаться активной навсегда." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" -msgstr "" +msgstr "отображается с - по" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" -msgstr "" +msgstr "Дато-ориентированная публикация" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" -msgstr "" +msgstr "избранное" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" -msgstr "" +msgstr "Избранное" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" -msgstr "" +msgstr "Ключевые слова" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "" +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "Ключевые слова игнорируют большинство поисковиков" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" -msgstr "" +msgstr "Описание" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." msgstr "" - -#: module/extensions/seo.py:17 +"Этот текст отображается в выдаче поисковиков. Но оно не используется " +"для SEO ранжирования. Текст длиннее 140 символов усекается." +#: module/extensions/seo.py:32 msgid "Search engine optimization" -msgstr "" +msgstr "SEO Оптимизация" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:239 msgid "Edit translation" msgstr "Изменить перевод" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:246 msgid "Create translation" msgstr "Создать перевод" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:254 msgid "translations" msgstr "переводы" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:28 msgid "This would create a loop in the hierarchy" -msgstr "" +msgstr "Это создало бы зацикливание в иерархии" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:72 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" - -#: module/medialibrary/modeladmins.py:58 +"Невозможно перезаписать с различным типом файла (попытка перезаписать " +"%(old_ext)s с %(new_ext)s)" +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "%(count)d медиа-файл успешно добавлен в %(category)s." +msgstr[1] "%(count)d медиа-файла успешно добавлены в %(category)s." +msgstr[2] "%(count)d медиа-файлов успешно добавлены в %(category)s." -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" -msgstr "" +msgstr "Добавить выбранные медиа-файлы в категорию" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" -msgstr "" +msgstr "ZIP файл экспортирован как %s" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" -msgstr "" +msgstr "Экспорт ZIP файла не удался: %s" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" -msgstr "" +msgstr "Экспортировать выбранные медиа-файлы как ZIP архив" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Предпросмотр" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "размер файла" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "создан" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "тип файла" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" -msgstr "" +msgstr "информация о файле" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" -msgstr "" +msgstr "%d файлов импортировано" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" -msgstr "" +msgstr "ZIP импорт не удался: %s" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" -msgstr "" +msgstr "Не получен входной файл" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "родитель" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "путь в URL" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "категория" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "категории" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" -msgstr "" +msgstr "копирайт" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Изображение" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Видео" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Аудио" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "Документ PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" -msgstr "" +msgstr "Флэш" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Текст" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" -msgstr "" +msgstr "Форматтированный текст" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" -msgstr "" +msgstr "Zip архив" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Двоичный" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "описание" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" -msgstr "" +msgstr "перевод медиа-файла" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" -msgstr "" +msgstr "переводы медиа-файлов" -#: module/page/forms.py:172 +#: module/page/forms.py:186 msgid "This URL is already taken by an active page." msgstr "Этот URL уже занят активной страницей." -#: module/page/forms.py:190 +#: module/page/forms.py:205 msgid "This URL is already taken by another active page." msgstr "Этот URL уже занят другой активной страницей." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:210 +msgid "This page does not allow attachment of child pages" +msgstr "Эта страница не позволяет создание дочерних страниц" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Другие параметры" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "в навигации" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" -msgstr "" +msgstr "Добавить дочернюю страницу" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" -msgstr "" +msgstr "Посмотреть на сайте" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" -msgstr "" +msgid "Add %(language)s translation of \"%(page)s\"" +msgstr "Добавить %(language)s перевод \"%(page)s\"" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" - -#: module/page/modeladmins.py:170 +"Содержание на языке по-умолчанию было скопировано в свежесозданную " +"страницу." +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" -msgstr "" +msgstr "Вы не имеете необходимые права на изменение этого объекта" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" -msgstr "" +msgstr "унаследованный" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "расширения" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" -msgstr "" +msgstr "активная?" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "активная" -#: module/page/models.py:175 -msgid "override URL" -msgstr "" +#: module/page/models.py:173 +#, fuzzy +msgid "This title is also used for navigation menu items." +msgstr "Этот заголовок также используется в навигации." #: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "Это используется для создания URL этой страницы" + +#: module/page/models.py:184 +msgid "override URL" +msgstr "переопределение URL" + +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." msgstr "" - -#: module/page/models.py:177 +"Переопределить целевой URL. Не забудьте добавить слеш в начале и в" +"конеце, если это локальный URL. Это влияет на навигацию и URL дочерних страниц." +#: module/page/models.py:190 msgid "redirect to" msgstr "редирект на" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." -msgstr "" +msgstr "Целевой URL для автоматических переадресации или первичный ключ страницы." -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" +msgstr "Кешированный URL" + +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" msgstr "" -#: module/page/models.py:395 +#: module/page/models.py:426 msgid "page" msgstr "страница" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "страницы" -#: module/page/extensions/excerpt.py:9 +#: module/page/extensions/excerpt.py:18 msgid "excerpt" -msgstr "" +msgstr "отрывок" -#: module/page/extensions/excerpt.py:10 +#: module/page/extensions/excerpt.py:21 msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" +msgstr "Добавьте краткий отрывок резюмируя содержание" -#: module/page/extensions/excerpt.py:12 +#: module/page/extensions/excerpt.py:25 msgid "Excerpt" -msgstr "" +msgstr "Отрывок" -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 msgid "navigation extension" -msgstr "" +msgstr "расширение навигации" -#: module/page/extensions/navigation.py:110 +#: module/page/extensions/navigation.py:119 msgid "" "Select the module providing subpages for this page if you need to customize " "the navigation." msgstr "" - -#: module/page/extensions/navigation.py:125 +"Выберите модуль который обеспечит подстраницы для этой страницы, если вам нужно настроить" +"навигацию." +#: module/page/extensions/navigation.py:134 msgid "Navigation extension" -msgstr "" +msgstr "Расширение навигации" -#: module/page/extensions/relatedpages.py:14 +#: module/page/extensions/relatedpages.py:21 msgid "Select pages that should be listed as related content." -msgstr "" +msgstr "Выберите страницы, которые должны быть отображены как похожие." -#: module/page/extensions/relatedpages.py:19 +#: module/page/extensions/relatedpages.py:26 msgid "Related pages" -msgstr "" +msgstr "Похожие страницы" -#: module/page/extensions/sites.py:16 +#: module/page/extensions/sites.py:21 msgid "Site" -msgstr "" +msgstr "Сайт" -#: module/page/extensions/symlinks.py:15 +#: module/page/extensions/symlinks.py:22 msgid "symlinked page" -msgstr "" +msgstr "страница привязанная символической ссылкой" -#: module/page/extensions/symlinks.py:16 +#: module/page/extensions/symlinks.py:23 msgid "All content is inherited from this page if given." -msgstr "" +msgstr "Все содержимое наследуется с этой страницы." -#: module/page/extensions/titles.py:13 +#: module/page/extensions/titles.py:19 msgid "content title" -msgstr "" +msgstr "Заголовок содержимого" -#: module/page/extensions/titles.py:14 +#: module/page/extensions/titles.py:22 msgid "The first line is the main title, the following lines are subtitles." -msgstr "" +msgstr "Первая строка — основной заголовок, следующие строки — подзаголовки." -#: module/page/extensions/titles.py:15 +#: module/page/extensions/titles.py:26 msgid "page title" msgstr "заголовок страницы" -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Заголовок страницы для окна браузера. По умолчанию = просто заголовку страницы." +#: module/page/extensions/titles.py:30 +#, fuzzy +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Заголовок страницы для окна браузера. По умолчанию = просто заголовку " +"страницы." -#: module/page/extensions/titles.py:43 +#: module/page/extensions/titles.py:60 msgid "Titles" msgstr "Заголовки" #: templates/admin/filter.html:3 #, python-format msgid " By %(filter_title)s " -msgstr "" +msgstr " По %(filter_title)s " #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" @@ -758,7 +781,9 @@ msgstr "Не выходит удалить элемент" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Не выходит удалить элемент, т.к. он является родителем как минимум для одного другого элемента." +msgstr "" +"Не выходит удалить элемент, т.к. он является родителем как минимум для " +"одного другого элемента." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -771,9 +796,8 @@ msgstr "Точно сменить шаблон? <br/> Все изменения #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -798,7 +822,7 @@ msgstr "Вставить перед этим элементом" #: templates/admin/feincms/content_editor.html:15 msgid "Copy content from the original" -msgstr "" +msgstr "Скопировать оригинальное содержимое" #: templates/admin/feincms/content_editor.html:19 msgid "Region empty" @@ -809,21 +833,22 @@ msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." msgstr "" - +"Контент автоматически унаследован от родительского узла. Чтобы переопределить это" +"поведение, добавьте содержимое." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Добавить элемент" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" -msgstr "" +msgstr "Добавить еще %(verbose_name)s" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" -msgstr "" +msgstr "Удалить" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Сохранить" @@ -861,40 +886,40 @@ msgstr "Начало" #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" -msgstr "" +msgstr "Восстановить удаленные %(verbose_name)s" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "" +msgstr "Нажмите кнопку Сохранить ниже, чтобы восстановить эту версию объекта." #: templates/admin/feincms/revision_form.html:12 msgid "History" -msgstr "" +msgstr "История" #: templates/admin/feincms/revision_form.html:13 #, python-format msgid "Revert %(verbose_name)s" -msgstr "" +msgstr "Восстановить %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "" +msgstr "Нажмите кнопку Сохранить ниже, чтобы восстановить эту версию объекта." -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" -msgstr "" +msgstr "Управление деревом" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" -msgstr "Свернуть дерево" +msgstr "Свернуть" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" -msgstr "Развернуть дерево" +msgstr "Развернуть" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" -msgstr "" +msgstr "Фильтр" #: templates/admin/feincms/page/page/item_editor.html:10 msgid "Edit on site" @@ -902,28 +927,28 @@ msgstr "Редактировать на сайте" #: templates/admin/feincms/page/page/item_editor.html:27 msgid "Add" -msgstr "" +msgstr "Добавить" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 msgid "Add media files to category" -msgstr "" +msgstr "Добавить медиа-файлы в категорию" #: templates/admin/medialibrary/add_to_category.html:11 msgid "Select category to apply:" -msgstr "" +msgstr "Выберите категорию для применения:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "" +msgstr "Следующие медиа-файлы будут добавлены в выбранную категорию:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" -msgstr "" +msgstr "Добавить в категорию" #: templates/admin/medialibrary/add_to_category.html:23 msgid "Cancel" -msgstr "" +msgstr "Отмена" #: templates/admin/medialibrary/mediafile/change_list.html:11 msgid "Bulk upload a ZIP file:" @@ -931,7 +956,7 @@ msgstr "Загрузить несколько файлов в ZIP-архиве:" #: templates/admin/medialibrary/mediafile/change_list.html:21 msgid "Overwrite" -msgstr "" +msgstr "Перезаписать" #: templates/admin/medialibrary/mediafile/change_list.html:24 msgid "Send" @@ -946,9 +971,14 @@ msgstr "%(comment_count)s комментариев." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" Пользователь %(comment_username)s сказал " +"(%(comment_submit_date)s)<br />\n" " " -msgstr "\n Пользователь %(comment_username)s сказал (%(comment_submit_date)s)<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -965,3 +995,12 @@ msgstr "Отправить" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Спасибо!" + +#~ msgid "table" +#~ msgstr "таблица" + +#~ msgid "tables" +#~ msgstr "таблицы" + +#~ msgid "data" +#~ msgstr "данные" From 83ee0dfd51f938ef53b217bd69fb961eab657930 Mon Sep 17 00:00:00 2001 From: Denis Popov <akadan47@gmail.com> Date: Fri, 23 May 2014 07:09:39 +0400 Subject: [PATCH 0964/1590] Fix translation --- feincms/locale/ru/LC_MESSAGES/django.mo | Bin 19648 -> 19649 bytes feincms/locale/ru/LC_MESSAGES/django.po | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/locale/ru/LC_MESSAGES/django.mo b/feincms/locale/ru/LC_MESSAGES/django.mo index c853de1cba925b90d5dc206e0f062deeec64c668..219424a75b726c4c1fd5fdc8e4f49969c4bbb518 100644 GIT binary patch delta 1245 zcmXZbTS$~a6u|MbO1W$|*KFIou$8%KhFPw+*2-El)6I+!iJ&&nt^}1}=tG|nNEn5% z4<ea8Rb&K`NvUj9MnMpL3q3_qPf<ZHh7yF(|M<<*Z_doOXU@!-eKF{IIp`Yw=(fZq zvMnUy7m?C3kxYzYI-bBnyo5bCWXvshz8^*p^G|UpzQUvU0rz21g-A7a;3^!&0KUQH z_`O1`g$-tzC}JW|DUyMWn1#o%2D`8WCvgIctDNtCU>@;5)P#ZUB5qyBEm(n??-b5q zH~R5nSfm&G!j^LaFJ-P^A_s5cX6(T!ynxj^ME>F<jNrYUBF*><TQR&#qy^&`!=LyN z8)`Tu&Y|AOm)%Z5`FoswD=h{aScu>Np2h>HyPSn4EX4`jioY?4fm-Lpb*QasF`hK@ zmr+~Ui|g=~F@br+Ur}$&O5N*Jlwr(A9}AVJ8yz%uq9(kJ`X(Nu_VhDq0W+v?Ahk|p z4W^^cZ$fQJ7_+bz7vXVd-I8_&`om7+Rn*G*Q8&DU+QTQPiQeLRv~e~5K`$=he)Tct zqUI|=EuhR;hgxte=HPks^8TccfhHcpjd&L|!Fv;b!j;4+^-imNSU?;`P1uIIQ8#Ae zb>n?pOgxR6_Z@11Gnk9>n92T<z27-e32LIls6A>k@ipTh>gydr9=uGOcpf#OuR){) zL#W@i8?T_=(17s)YT;98=~X8g6yi73zoDnmxq)(H1ohw1jBbqKAv|N^DbyQ#jaqmT z^KlkEm>qRm7)0H#3iY7%Q7K-yq9aV`hcV+h)E;%3IF8!$;jyk|b}((+PT0@v@px0H YCM9_z-XHR(t+glZ=XPRjG?ecD54moh`~Uy| delta 1263 zcmXZbTS!z<6oBESV3<^DY1wEtdCjD(9330Gm}cg!EV@CIf_6cAu)@fPI3ko8QD9J+ z*;7SP(3luHT}Y!Kh}r|aL{U%Opclg;La={%_S1LPI%n2id#^nsJrU1(B7*Otok<Z{ z=@Us(3q%sI8so45bMOeZW3M%((EYv-W5_?m890J_@C{br62Hi5Jc@~U9~a^aoP}Tf z;!G_tP9m2?YLUontU?d&#S%P$$8Z>jap@}eyKk6I{13HYYCt4f-(wyYqSiZrf3OXc zu%%e!G<Fp`?hfK;GnPa$p2u8l#}Kw)@fwl8cn{0)=30?D{DHeLuufzLc4Gs6$Gccr zBJve~qn^me^=?BMrS7_ZhldPal;UMPh_yJ0%~;E7`8b3t@F!+r>IQem<*1|DZryM5 z$5BUl3K!v3>tjqO{)BpBPGq^;QM@$+=kmgjy3l58D{8@OsCS|tb*3Ls8yG{q1Cbj= z=3^{sJ_mIq0rX%QM&Um9y(3LL=nq@19jKjMKwa=U>I?@^3%$fNe2eq&7sg`@=c|`7 z1+`u_Y6CuNIcmc@F$E7}Joit!c+kSVn2k433%s`Rdz?cYvB@1(A}%HlpcZUIU8oI{ z@vQY0P9q*gt@{eK!7*Hb6PUpI;;D3Zl!sbq8|sW2ZQN<Sf_i)JAQxUnZ9IWmFtJKx zIp(8&*JM43dP0}1w^17pp`%A_c*w!esDH!h)$R!tSW8j=9a}IO>v1a{vT+FY#Ga!z zZZH$aF$O&~?g%qc*DFHZXhn@In>wQ1B=p02YcuMMT5a5oI`h7PwwWd?YAD<hK6kOs mSCVE1!)Ltaf!91S!EmPunnz~PYlcXfka<dWaG>88m-HV*L#_`1 diff --git a/feincms/locale/ru/LC_MESSAGES/django.po b/feincms/locale/ru/LC_MESSAGES/django.po index e10fff887..ef920ccd0 100644 --- a/feincms/locale/ru/LC_MESSAGES/django.po +++ b/feincms/locale/ru/LC_MESSAGES/django.po @@ -656,8 +656,8 @@ msgid "" "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -"Переопределить целевой URL. Не забудьте добавить слеш в начале и в" -"конеце, если это локальный URL. Это влияет на навигацию и URL дочерних страниц." +"Переопределение целевой URL. Не забудьте добавить слэш в начале и в " +"конце, если это локальный URL. Это влияет на навигацию и URL дочерних страниц." #: module/page/models.py:190 msgid "redirect to" msgstr "редирект на" From d5f354ab35042d7a9c3e7dc35581bf78b5e5f600 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 27 May 2014 10:30:49 +0200 Subject: [PATCH 0965/1590] django-mptt 0.6.1 is compatible with the upcoming Django 1.7 --- tests/tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tox.ini b/tests/tox.ini index b820b3e7c..9f7934047 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -86,7 +86,7 @@ deps = basepython = python2.7 deps = https://github.com/django/django/zipball/stable/1.7.x - --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev + django-mptt==0.6.1 Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 @@ -116,7 +116,7 @@ deps = basepython = python3.2 deps = https://github.com/django/django/zipball/stable/1.7.x - --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev + django-mptt==0.6.1 Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 @@ -146,7 +146,7 @@ deps = basepython = python3.3 deps = https://github.com/django/django/zipball/stable/1.7.x - --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev + django-mptt==0.6.1 Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 From 9b3366d2be95b37a7acd0fb09d8d41425732a4a3 Mon Sep 17 00:00:00 2001 From: Sumit Datta <sumitdatta@gmail.com> Date: Tue, 27 May 2014 19:27:42 +0530 Subject: [PATCH 0966/1590] Minor updates to installation.rst, updated LANGUAGES settings href, cleaned INSTALLED_APPS --- docs/installation.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 2103ce2fe..5761e0f23 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -47,9 +47,13 @@ TinyMCE_ works out of the box and is recommended. Configuration ============= -There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS``, -most commonly you'll want to add ``feincms``, ``mptt``, ``feincms.module.page`` and -``feincms.module.medialibrary``. +There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS``, most commonly you'll want to add:: + + feincms, + mptt, + feincms.module.page, + feincms.module.medialibrary + The customized administration interface needs some media and javascript libraries which you have to make available to the browser. FeinCMS uses Django's ``django.contrib.staticfiles`` application for this purpose, the media files will @@ -67,4 +71,4 @@ pages and this is the most advanced module of FeinCMS too. Please proceed to :ref:`page` to find out how you can get the page module up and running. -.. _settings: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#how-django-discovers-language-preference +.. _settings: https://docs.djangoproject.com/en/dev/ref/settings/#languages From 694a664654a9cb6f4a497588eab68f4b7d67fb27 Mon Sep 17 00:00:00 2001 From: Charlie Denton <charlie@meshy.co.uk> Date: Fri, 30 May 2014 15:13:52 +0100 Subject: [PATCH 0967/1590] Set up test scenario Show that creating content type on custom model throws no error. --- tests/testapp/content.py | 6 ++++++ tests/testapp/models.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/testapp/content.py diff --git a/tests/testapp/content.py b/tests/testapp/content.py new file mode 100644 index 000000000..24f79b6e2 --- /dev/null +++ b/tests/testapp/content.py @@ -0,0 +1,6 @@ +from django.db import models + + +class CustomContentType(models.Model): + class Meta: + abstract = True diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 23ef36d77..ced6fc823 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -6,6 +6,7 @@ from django.utils.text import capfirst from django.utils.translation import ugettext_lazy as _ +from feincms.models import create_base_model from feincms.module.blog.models import Entry, EntryAdmin from feincms.module.page.models import Page from feincms.content.raw.models import RawContent @@ -18,6 +19,7 @@ from mptt.models import MPTTModel +from .content import CustomContentType Page.register_templates({ 'key': 'base', @@ -136,3 +138,13 @@ def __str__(self): str('categories'), models.ManyToManyField(Category, blank=True, null=True)) EntryAdmin.list_filter += ('categories',) + + +class MyModel(create_base_model()): + pass + + +MyModel.register_regions(('main', 'Main region')) + + +MyModel.create_content_type(CustomContentType) From d5aa20c93fd97e930512d89e1821e3c6b366413b Mon Sep 17 00:00:00 2001 From: Charlie Denton <charlie@meshy.co.uk> Date: Fri, 30 May 2014 15:20:00 +0100 Subject: [PATCH 0968/1590] Show that create_content_type modifies current context --- tests/testapp/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index ced6fc823..f2ae0c3a4 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -147,4 +147,6 @@ class MyModel(create_base_model()): MyModel.register_regions(('main', 'Main region')) +unchanged = CustomContentType MyModel.create_content_type(CustomContentType) +assert CustomContentType is unchanged From 68364b9be3fa93882ab260dfa65374d1b7a00ef0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 3 Jun 2014 13:34:09 +0200 Subject: [PATCH 0969/1590] feincms_languagelinks should not link to inactive pages --- docs/releases/1.10.rst | 3 +++ feincms/module/extensions/translations.py | 13 ++++++++++--- tests/testapp/tests/test_page.py | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index 1ca75f270..98038bfc3 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -41,6 +41,9 @@ Notable features and improvements * The bundled versions of jQuery and jQuery UI have been updated to 1.11.1 and 1.10.3 respectively. +* ``feincms_languagelinks`` does not return page URLs leading to inactive + pages anymore. + Bugfixes ======== diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 10065b685..16c44bdca 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -191,12 +191,19 @@ def get_redirect_to_target(self, request): def available_translations(self): if not self.id: # New, unsaved pages have no translations return [] + + filter_active = lambda queryset: queryset + if hasattr(cls.objects, 'apply_active_filters'): + filter_active = cls.objects.apply_active_filters + if is_primary_language(self.language): - return self.translations.all() + return filter_active(self.translations.all()) elif self.translation_of: # reuse prefetched queryset, do not filter it - res = [t for t in list(self.translation_of.translations.all()) - if t.language != self.language] + res = [ + t for t + in filter_active(self.translation_of.translations.all()) + if t.language != self.language] res.insert(0, self.translation_of) return res else: diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 5a40a1edb..239d204a2 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -521,6 +521,10 @@ def test_11_translations(self): page1 = Page.objects.get(pk=1) page2 = Page.objects.get(pk=2) + page1.active = True + page1.save() + + page2.active = True page2.language = 'de' page2.save() From 22df57f44e94f65ea164f31020d911b4e067e2d7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 3 Jun 2014 14:09:45 +0200 Subject: [PATCH 0970/1590] Line length --- feincms/content/application/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index d2422f671..8bf5c340e 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -210,11 +210,12 @@ def __init__(self, *args, **kwargs): self.custom_fields.update( get_fields(self, *args, **kwargs)) + params = self.instance.parameters for k, v in self.custom_fields.items(): - v.initial = self.instance.parameters.get(k) + v.initial = params.get(k) self.fields[k] = v - if k in self.instance.parameters: - self.fields[k].initial = self.instance.parameters[k] + if k in params: + self.fields[k].initial = params[k] def save(self, commit=True, *args, **kwargs): # Django ModelForms return the model instance from save. We'll From 68c28b0bdbe022280047e126c78d2fec9ad2d58d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 12 Jun 2014 11:30:14 +0200 Subject: [PATCH 0971/1590] Fix #508: The request context processor is required --- docs/installation.rst | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 5761e0f23..59b3d8445 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -47,19 +47,28 @@ TinyMCE_ works out of the box and is recommended. Configuration ============= -There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS``, most commonly you'll want to add:: +There isn't much left to do apart from adding a few entries to +``INSTALLED_APPS``, most commonly you'll want to add:: feincms, mptt, feincms.module.page, feincms.module.medialibrary +Also, you should add the request context processor to the list of +``TEMPLATE_CONTEXT_PROCESSORS``, the template tag and the administration +interface require it:: + + django.core.context_processors.request + The customized administration interface needs some media and javascript -libraries which you have to make available to the browser. FeinCMS uses Django's -``django.contrib.staticfiles`` application for this purpose, the media files will -be picked up automatically by the ``collectstatic`` management command. +libraries which you have to make available to the browser. FeinCMS uses +Django's ``django.contrib.staticfiles`` application for this purpose, the media +files will be picked up automatically by the ``collectstatic`` management +command. -If your website is multi-language you have to define ``LANGUAGES`` in the settings_. +If your website is multi-language you have to define ``LANGUAGES`` in the +settings_. Please note that the ``feincms`` module will not create or need any database tables, but you need to put it into ``INSTALLED_APPS`` because otherwise the From fe4458e42924dbd35c11b8012079989e0651d726 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 14 Jun 2014 10:59:01 +0200 Subject: [PATCH 0972/1590] flake8 --- feincms/content/application/models.py | 5 +++-- tests/testapp/tests/test_page.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 919eb1bbf..bdc328ef5 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -212,8 +212,9 @@ def __init__(self, *args, **kwargs): for k, v in self.custom_fields.items(): self.fields[k] = v - if k in self.instance.parameters: - self.fields[k].initial = self.instance.parameters[k] + params = self.instance.parameters + if k in params: + self.fields[k].initial = params[k] def save(self, commit=True, *args, **kwargs): # Django ModelForms return the model instance from save. We'll diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 8a275ecfb..96b6f08e4 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1423,7 +1423,8 @@ def test_25_applicationcontent(self): # Check if admin_fields get populated correctly app_ct = page.applicationcontent_set.all()[0] - app_ct.parameters = '{"custom_field":"val42", "exclusive_subpages": false}' + app_ct.parameters =\ + '{"custom_field":"val42", "exclusive_subpages": false}' app_ct.save() r = self.client.get('/admin/page/page/%d/' % page.id) self.assertContains(r, 'val42') From 79f285205072a2e3b421ffa6832e4199a6b861f0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 15 Jun 2014 21:28:03 +0200 Subject: [PATCH 0973/1590] tox: Remove an unnecessary script since switching to zipballs for Django Also see changes to tox.ini in d96a4b4274e82279c2b31032d9c26bd2cbbbffe7. --- tests/tox-update-venvs.sh | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100755 tests/tox-update-venvs.sh diff --git a/tests/tox-update-venvs.sh b/tests/tox-update-venvs.sh deleted file mode 100755 index 5832dbfec..000000000 --- a/tests/tox-update-venvs.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -( - cd .tox/py27-1.7.X - bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev -) -( - cd .tox/py32-1.7.X - bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev -) -( - cd .tox/py33-1.7.X - bin/pip install -U --editable=git+git://github.com/django/django.git@master#egg=django-dev -) From 3f9df0e73fce0ad1aa0b8aac2c3769b237a03a5d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 15 Jun 2014 21:59:25 +0200 Subject: [PATCH 0974/1590] Fix #510: Document settings --- docs/index.rst | 1 + docs/settings.rst | 141 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 docs/settings.rst diff --git a/docs/index.rst b/docs/index.rst index 5c70ef46c..18e2cbfee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -54,6 +54,7 @@ Contents integration medialibrary templatetags + settings migrations versioning advanced/index diff --git a/docs/settings.rst b/docs/settings.rst new file mode 100644 index 000000000..f514a52f6 --- /dev/null +++ b/docs/settings.rst @@ -0,0 +1,141 @@ +.. _settings: + +======== +Settings +======== + +FeinCMS has a few installation-wide settings which you might want to customize. + +The default settings can be found inside :mod:`feincms.default_settings`. +FeinCMS reads the settings from :mod:`feincms.settings` -- values should be +overridden by placing them in your project's settings. + + +Content type specific settings +============================== + +``FEINCMS_UPLOAD_PREFIX``: Defaults to ``''``. Defines a prefix which is used +for file and image content uploads (not used by the media library). + + +Media library settings +====================== + +``FEINCMS_MEDIALIBRARY_UPLOAD_TO``: Defaults to ``medialibrary/%Y/%m``. Defines +the location of newly uploaded media files. + +``FEINCMS_MEDIALIBRARY_THUMBNAIL``: Defaults to +``feincms.module.medialibrary.thumbnail.default_admin_thumbnail``. The path to +a function which should return the URL to a thumbnail or ``None`` for the +mediafile instance passed as first argument. + +``FEINCMS_MEDIAFILE_OVERWRITE``: Defaults to ``False``. Set this to ``True`` +if uploads should replace previous files using the same path if possible. This +allows copy-pasted paths to work, but prevents using far future expiry headers +for media files. Also, it might not work with all storage backends. + + +Rich text settings +================== + +``FEINCMS_RICHTEXT_INIT_TEMPLATE``: Defaults to +``admin/content/richtext/init_tinymce.html``. The template which contains the +initialization snippet for the rich text editor. Bundled templates are: + +* ``admin/content/richtext/init_tinymce.html`` for TinyMCE 3.x. +* ``admin/content/richtext/init_tinymce4.html`` for TinyMCE 4.x. +* ``admin/content/richtext/init_ckeditor.html`` for CKEditor. + +``FEINCMS_RICHTEXT_INIT_CONTEXT``: Defaults to +``{'TINYMCE_JS_URL': '<<MEDIA_URL>>js/tiny_mce/tiny_mce.js'}``. A dictionary +which is passed to the template mentioned above. Please refer to the templates +directly to see all available variables. + + +Admin media settings +==================== + +``FEINCMS_JQUERY_NO_CONFLICT``: Defaults to ``False``. Django admin's jQuery is +not available as ``$`` or ``jQuery`` in the browser, but only as +``django.jQuery``. FeinCMS' jQuery can be made available only as +``feincms.jQuery`` by setting this variable to ``True``. Scripts should use +``feincms.jQuery`` anyway. + + +Settings for the tree editor +============================ + +``FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS``: Defaults to ``False``. When this +setting is ``True``, the tree editor shows all objects on a single page, and +also shows all ancestors up to the roots in filtered lists. + + +``FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS``: Defaults to ``False``. Enables +checking of object level permissions. + + +Settings for the page module +============================ + +``FEINCMS_FRONTEND_EDITING``: Defaults to ``False``. Activate this to show +the frontend editing button in the page change form. + +``FEINCMS_USE_PAGE_ADMIN``: Defaults to ``True``. The page model admin module +automatically registers the page model with the default admin site if this is +active. Set to ``False`` if you have to configure the page admin module +yourself. + +``FEINCMS_DEFAULT_PAGE_MODEL``: Defaults to ``page.Page``. The page model used +by :mod:`feincms.module.page`. + +``FEINCMS_ALLOW_EXTRA_PATH``: Defaults to ``False``. Activate this to allow +random gunk after a valid page URL. The standard behavior is to raise a 404 +if extra path elements aren't handled by a content type's ``process()`` method. + +``FEINCMS_TRANSLATION_POLICY``: Defaults to ``STANDARD``. How to switch +languages. + +* ``'STANDARD'``: The page a user navigates to sets the site's language + and overwrites whatever was set before. +* ``'EXPLICIT'``: The language set has priority, may only be overridden + by explicitely a language with ``?set_language=xx``. + +``FEINCMS_CMS_404_PAGE``: Defaults to ``None``. Set this if you want the page +handling mechanism to try and find a CMS page with that path if it encounters +a page not found situation. + +``FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED``: Defaults to ``False``. Prevent +changing template within admin for pages which have been allocated a Template +with ``singleton=True`` -- template field will become read-only for singleton +pages. + +``FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED``: Defaults to ``False``. +Prevent admin page deletion for pages which have been allocated a Template with +``singleton=True``. + + +Settings for HTML validation +============================ + +These settings are currently only used by the bundled rich text content type. + +``FEINCMS_TIDY_HTML``. Defaults to ``False``. If ``True``, HTML will be run +through a tidy function before saving. + +``FEINCMS_TIDY_SHOW_WARNINGS``: Defaults to ``True``. If ``True``, displays +form validation errors so the user can see how their HTML has been changed. + +``FEINCMS_TIDY_ALLOW_WARNINGS_OVERRIDE``: Defaults to ``True``. If ``True``, +users will be allowed to ignore HTML warnings (errors are always blocked). + +``FEINCMS_TIDY_FUNCTION``: Defaults to ``feincms.utils.html.tidy.tidy_html``. +Name of the tidy function - anything which takes ``(html)`` and returns +``(html, errors, warnings)`` can be used. + + +Various settings +================ + +``FEINCMS_THUMBNAIL_DIR``: Defaults to ``_thumbs/``. Defines a prefix for media +file thumbnails. This allows you to easily remove all thumbnails without fear +of removing files belonging to image and file fields. From aa2cddf12eb34fecbfabc42d7d67c7264c70b36f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 17 Jun 2014 14:04:53 +0200 Subject: [PATCH 0975/1590] Fix #532: Make the template fallback Python3-compatible Thanks to Nils Fredrik Gjerull for the report. --- feincms/models.py | 2 +- tests/testapp/tests/test_page.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index 2b6021f7a..7b3eb5779 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -400,7 +400,7 @@ def _template(self): # return first template as a fallback if the template # has changed in-between return self._feincms_templates[ - self._feincms_templates.keys()[0]] + list(self._feincms_templates.keys())[0]] cls.template = property(_template) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 8a275ecfb..07f677f8d 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1720,3 +1720,8 @@ def test_37_invalid_parent(self): page1.parent = page3 self.assertRaises(InvalidMove, page1.save) + + def test_38_invalid_template(self): + page = Page() + page.template_key = 'test' + self.assertEqual(page.template.key, 'base') From f03dda7f27c738b42c52119f0c7edf4e77cd8243 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 17 Jun 2014 14:06:20 +0200 Subject: [PATCH 0976/1590] FeinCMS v1.9.4 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 823e59932..fe3eeaf33 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 9, 3) +VERSION = (1, 9, 4) __version__ = '.'.join(map(str, VERSION)) From a97c74b4e7b0ee7c6cc09351c2ea670d4fface40 Mon Sep 17 00:00:00 2001 From: Wim Feijen <wim@go2people.nl> Date: Wed, 18 Jun 2014 22:25:41 +0200 Subject: [PATCH 0977/1590] Update installation.rst Clarify documentation and be specific about the supported Django versions. --- docs/installation.rst | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 5761e0f23..c9a06ac23 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -7,26 +7,20 @@ Installation instructions Installation ============ -This document describes the steps needed to get FeinCMS up and running. +This document describes the steps needed to install FeinCMS. -FeinCMS is based on Django, so you need a working Django_ installation -first. The minimum support version of Django_ is the 1.4 line of releases. +FeinCMS requires a working installation of Django_ version 1.4, 1.5 or 1.6. See the Django_ documentation for how to install and configure Django. -You can download a stable release of FeinCMS using ``pip``:: +You can download a stable release of FeinCMS using ``pip``. Pip will install feincms and its dependencies. Dependencies which are automatically installed are: +feedparser_, Pillow_ and django-mptt_. $ pip install feincms -Pip will install feincms and its dependencies. It will however not install -documentation, tests or the example project which comes with the development version, -which you can download using the Git_ version control system:: +In order to install documentation, tests or an example project, install from the Git_ repository instead:: $ git clone git://github.com/feincms/feincms.git -Feincms, some content types or cleaning modules are dependent on the following apps, which are installed when using pip: -feedparser_, Pillow_ and django-mptt_. - -However, django-tagging_ is not installed because the blog module that uses it is merely a proof of -concept. If you are looking to implement a blog, check out elephantblog_. +If you are looking to implement a blog, check out elephantblog_. You will also need a Javascript WYSIWYG editor of your choice (Not included). TinyMCE_ works out of the box and is recommended. @@ -47,7 +41,7 @@ TinyMCE_ works out of the box and is recommended. Configuration ============= -There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS``, most commonly you'll want to add:: +There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS``. Most commonly you'll want to add:: feincms, mptt, @@ -56,7 +50,7 @@ There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS` The customized administration interface needs some media and javascript libraries which you have to make available to the browser. FeinCMS uses Django's -``django.contrib.staticfiles`` application for this purpose, the media files will +``django.contrib.staticfiles`` application for this purpose. The media files will be picked up automatically by the ``collectstatic`` management command. If your website is multi-language you have to define ``LANGUAGES`` in the settings_. From 8b93d797d63c4819fefc9fc1b85a2dfa125db27a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Thu, 19 Jun 2014 11:57:53 +0200 Subject: [PATCH 0978/1590] Rewrap a few lines --- docs/installation.rst | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index c9a06ac23..f9890c51e 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -9,14 +9,17 @@ Installation This document describes the steps needed to install FeinCMS. -FeinCMS requires a working installation of Django_ version 1.4, 1.5 or 1.6. See the Django_ documentation for how to install and configure Django. +FeinCMS requires a working installation of Django_ version 1.4, 1.5 or 1.6. See +the Django_ documentation for how to install and configure Django. -You can download a stable release of FeinCMS using ``pip``. Pip will install feincms and its dependencies. Dependencies which are automatically installed are: -feedparser_, Pillow_ and django-mptt_. +You can download a stable release of FeinCMS using ``pip``. Pip will install +feincms and its dependencies. Dependencies which are automatically installed +are: feedparser_, Pillow_ and django-mptt_. $ pip install feincms -In order to install documentation, tests or an example project, install from the Git_ repository instead:: +In order to install documentation, tests or an example project, install from +the Git_ repository instead:: $ git clone git://github.com/feincms/feincms.git @@ -41,7 +44,8 @@ TinyMCE_ works out of the box and is recommended. Configuration ============= -There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS``. Most commonly you'll want to add:: +There isn't much left to do apart from adding a few entries to +``INSTALLED_APPS``. Most commonly you'll want to add:: feincms, mptt, @@ -49,11 +53,13 @@ There isn't much left to do apart from adding a few entries to ``INSTALLED_APPS` feincms.module.medialibrary The customized administration interface needs some media and javascript -libraries which you have to make available to the browser. FeinCMS uses Django's -``django.contrib.staticfiles`` application for this purpose. The media files will -be picked up automatically by the ``collectstatic`` management command. +libraries which you have to make available to the browser. FeinCMS uses +Django's ``django.contrib.staticfiles`` application for this purpose. The media +files will be picked up automatically by the ``collectstatic`` management +command. -If your website is multi-language you have to define ``LANGUAGES`` in the settings_. +If your website is multi-language you have to define ``LANGUAGES`` in the +settings_. Please note that the ``feincms`` module will not create or need any database tables, but you need to put it into ``INSTALLED_APPS`` because otherwise the From e158455631cbb3ce972cc2c406a75513b6556c67 Mon Sep 17 00:00:00 2001 From: ilmarsm <ilmars@gmail.com> Date: Wed, 25 Jun 2014 18:08:27 +0300 Subject: [PATCH 0979/1590] Better way to get to current user instance Old way don't work on Django 1.6.5 with Python 3.4 --- feincms/templatetags/feincms_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 666db0bc0..b8d7cc49d 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -83,7 +83,7 @@ def show_content_type_selection_widget(context, region): """ {% show_content_type_selection_widget region %} """ - user = context['request'].user + user = context.get('user') grouped = {} ungrouped = [] for ct in region._content_types: From 1c82b2ee3e508582495bd8c6787672fda3e8788f Mon Sep 17 00:00:00 2001 From: Charlie Denton <charlie@meshy.co.uk> Date: Mon, 30 Jun 2014 15:25:38 +0100 Subject: [PATCH 0980/1590] Don't monkeypatch content types into other modules Fixes https://github.com/feincms/feincms/pull/528 --- feincms/models.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 2b6021f7a..74d54555f 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -702,8 +702,6 @@ class Meta(feincms_content_base.Meta): attrs, ) cls._feincms_content_types.append(new_type) - # For consistency's sake, also install the new type in the module - setattr(sys.modules[cls.__module__], class_name, new_type) if hasattr(getattr(new_type, 'process', None), '__call__'): cls._feincms_content_types_with_process.append(new_type) From 91df9d4809e035e682e882ae58f23945a91491f2 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" <mjl@laubach.at> Date: Tue, 1 Jul 2014 10:59:39 +0200 Subject: [PATCH 0981/1590] Do not raise an exception (and thus crash the site) if there is no primary language translation for a page. Instead, just use the current page. While this obviously should not happen if the site is correctly filled with content, a page that has no original translation in the primary language can easily be added. Switching languages would then raise an exception, which translates to an ugly 500 error. Just use the current page if that happens and hope for the best. --- feincms/module/extensions/translations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 16c44bdca..0f1fbc4d8 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -215,7 +215,9 @@ def get_original_translation(self, *args, **kwargs): return self if self.translation_of: return self.translation_of - raise self.DoesNotExist + logger.debug("Page pk=%d (%s) has no primary language translation (%s)", + self.pk, self.language, django_settings.LANGUAGES[0][0]) + return self @monkeypatch_property(cls) def original_translation(self): From a855e3d5d2bf98b0f04fa3c91879b8ffbd363212 Mon Sep 17 00:00:00 2001 From: niklaushug <nh@feinheit.ch> Date: Thu, 3 Jul 2014 17:51:48 +0200 Subject: [PATCH 0982/1590] Update init_tinymce4.html add 'menubar : false' in tinymce_options --- feincms/templates/admin/content/richtext/init_tinymce4.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/templates/admin/content/richtext/init_tinymce4.html b/feincms/templates/admin/content/richtext/init_tinymce4.html index 6a3f7b6f5..f8bcd789a 100644 --- a/feincms/templates/admin/content/richtext/init_tinymce4.html +++ b/feincms/templates/admin/content/richtext/init_tinymce4.html @@ -22,7 +22,8 @@ paste_auto_cleanup_on_paste: true, relative_urls: false, invalid_elements: 'script', - statusbar: false + statusbar: false, + menubar : false {% endblock %} }; From dcbc38c895ac5ca8a64e775155ea21f2d1fe4f8c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 8 Jul 2014 16:35:10 +0200 Subject: [PATCH 0983/1590] Point people to FeinCMS in a Box, it is probably the better example than the one bundled with FeinCMS --- README.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.rst b/README.rst index a3976e2ba..ea4c30a03 100644 --- a/README.rst +++ b/README.rst @@ -77,6 +77,13 @@ Visit these sites * See the Google Groups page at http://groups.google.com/group/django-feincms * FeinCMS on github: https://github.com/feincms/feincms/ +Try out FeinCMS in a Box +------------------------ + +`FeinCMS in a Box <https://github.com/matthiask/feincms-in-a-box>`_ is a +prepackaged installation of FeinCMS with a few additional modules and a setup +script. Try it out! + IRC --- From 1405970097f843dad4bc8e0ce942a5efd86c8ff2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 8 Jul 2014 16:44:30 +0200 Subject: [PATCH 0984/1590] Update the release notes for 1.10 --- docs/releases/1.10.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index 98038bfc3..36f3a6379 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -23,16 +23,20 @@ isn't yet when creating content types). Backwards-incompatible changes ============================== +Shouldn't have any. + Removal of deprecated features ------------------------------ -* +None. New deprecations ================ +None. + Notable features and improvements @@ -44,10 +48,25 @@ Notable features and improvements * ``feincms_languagelinks`` does not return page URLs leading to inactive pages anymore. +* The application content type form does not mysteriously forget values + anymore. + +* ``Page.get_original_translation`` returns the current page instead of + crashing if there is no original translation. + +* ``feincms_nav`` returns an empty list instead of crashing if the page + argument is ``None``. + +* Settings are documented again. + Bugfixes ======== +* Bulk deletion of pages in the tree editor shouldn't lead to MPTT data + corruption anymore. This didn't happen often before either, but shouldn't + happen anymore at all. + Compatibility with Django and other apps ======================================== From 036d7e48fc925b82e6f5e7628b8472b035ef0249 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 8 Jul 2014 16:48:55 +0200 Subject: [PATCH 0985/1590] Better be safe and do not introduce a different dependency if not necessary Refs #534. --- feincms/templatetags/feincms_tags.py | 39 +++++++++++++++++----------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 44879c14b..cc09f3c30 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -84,24 +84,33 @@ def show_content_type_selection_widget(context, region): """ {% show_content_type_selection_widget region %} """ - user = context.get('user') + if 'request' in context: + user = context['request'].user + elif user in context: + user = context['user'] + else: + user = None + grouped = {} ungrouped = [] - for ct in region._content_types: - # Skip cts that we shouldn't be adding anyway - opts = ct._meta - perm = opts.app_label + "." + get_permission_codename('add', opts) - if not user.has_perm(perm): - continue - - ct_info = (ct.__name__.lower(), ct._meta.verbose_name) - if hasattr(ct, 'optgroup'): - if ct.optgroup in grouped: - grouped[ct.optgroup].append(ct_info) + + if user: + for ct in region._content_types: + # Skip cts that we shouldn't be adding anyway + opts = ct._meta + perm = opts.app_label + "." + get_permission_codename('add', opts) + if not user.has_perm(perm): + continue + + ct_info = (ct.__name__.lower(), ct._meta.verbose_name) + if hasattr(ct, 'optgroup'): + if ct.optgroup in grouped: + grouped[ct.optgroup].append(ct_info) + else: + grouped[ct.optgroup] = [ct_info] else: - grouped[ct.optgroup] = [ct_info] - else: - ungrouped.append(ct_info) + ungrouped.append(ct_info) + return {'grouped': grouped, 'ungrouped': ungrouped} From f8310b0cd8686f70ff525eb893174885a2b85ae7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 8 Jul 2014 17:27:17 +0200 Subject: [PATCH 0986/1590] Update AUTHORS (echo -e "The authors of FeinCMS are:\n" ; git shortlog -ns | sed -e 's/[\t ]*[0-9]*/* /' | tr -d '\011') > AUTHORS --- AUTHORS | 94 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/AUTHORS b/AUTHORS index e7fa8eec3..0f3935d36 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,81 +10,87 @@ The authors of FeinCMS are: * Bjorn Post * Julien Phalip * Daniel Renz -* Skylar Saveland -* Simon Schürpf -* Matt Dawson * Stefan Reinhard -* Simon Schmid +* Matt Dawson +* Simon Schürpf +* Skylar Saveland * Marc Egli * Psyton +* Simon Schmid * Greg Turner +* Charlie Denton +* Greg Taylor * Maarten van Gompel (proycon) * Bjarni Thorisson -* Greg Taylor -* Julian Bez +* Urs Breton * Jonas * Antoni Aloy -* Urs Breton +* Julian Bez +* Marc Tamlyn +* Toby White * Sander van Leeuwen * Nico Echaniz * Afonso Fernández Nogueira -* Toby White -* Charlie Denton +* Max Peterson * Vítor Figueiró -* Marc Tamlyn * Martin Mahner -* Max Peterson +* Torkn +* Andrew D. Ball * Brian Macdonald -* Maarten Draijer * Eric Delord * Gabriel Kovacs +* Maarten Draijer * adsworth -* Andrew D. Ball -* Torkn -* Raphael Jasjukaitis -* Michael Bashkirov +* Maciek Szczesniak * Fabian Vogler * Fabian Germann -* Wil Tan +* Denis Popov * Vaclav Klecanda -* tayg -* Håvard Grimelid +* Raphael Jasjukaitis * Cellarosi Marco -* Mikhail Korobov -* Maciek Szczesniak +* Wil Tan +* Michael Bashkirov * Richard A +* tayg +* Mikhail Korobov * Marco Fucci +* Håvard Grimelid +* Riccardo Coroneo +* Richard Bolt +* Rico Moorman +* Denis Martinez +* Sebastian Hillig +* Silvan Spross +* David Evans +* Darryl Woods +* Daniele Procida +* Artur Barseghyan +* Anshuman Bhaduri +* Andrin Heusser +* Sumit Datta +* Sun Liwen * Tobias Haffner -* Alen Mujezinovic -* Alex Kamedov -* Andi Albrecht * Andrey Popelo -* Andrin Heusser -* Anshuman Bhaduri -* Daniele Procida -* Darryl Woods -* David Evans -* Denis Martinez -* Domas Lapinskas -* George Karpenkov -* Harro van der Klauw -* Jay Yu -* Jimmy Ye -* Jonas Svensson +* Andi Albrecht +* Alex Kamedov +* Valtron +* Alen Mujezinovic +* Wim Feijen +* Wouter van der Graaf +* ilmarsm * Laurent Paoletti +* svleeuwen * Livio Lunin +* Jonas Svensson +* Jimmy Ye +* Jay Yu * Marco Cellarosi * Mark Renton +* Harro van der Klauw * Mason Hugus +* George Karpenkov * Mikkel Hoegh +* Domas Lapinskas * Olekasnadr Gula * Paul Garner * Piet Delport -* Riccardo Coroneo -* Richard Bolt -* Rico Moorman -* Sebastian Hillig -* Silvan Spross -* Valtron -* Wouter van der Graaf -* svleeuwen From 1f5d0537a783b202fc7ef0884115b8be8caa44c4 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 8 Jul 2014 17:31:59 +0200 Subject: [PATCH 0987/1590] flake8 complains --- feincms/module/extensions/translations.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 0f1fbc4d8..8f330c8ea 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -215,8 +215,9 @@ def get_original_translation(self, *args, **kwargs): return self if self.translation_of: return self.translation_of - logger.debug("Page pk=%d (%s) has no primary language translation (%s)", - self.pk, self.language, django_settings.LANGUAGES[0][0]) + logger.debug( + "Page pk=%d (%s) has no primary language translation (%s)", + self.pk, self.language, django_settings.LANGUAGES[0][0]) return self @monkeypatch_property(cls) From 1d526077a2e978afe1267d092863b7f418479089 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@406.ch> Date: Tue, 8 Jul 2014 20:52:04 +0200 Subject: [PATCH 0988/1590] Update the deprecation timeline for 1.10 --- docs/deprecation.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index 36dc07668..81cabf78a 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -101,3 +101,9 @@ will be issued for at least two releases. * The ``_feincms_extensions`` attribute on the page model and on models inheriting ``ExtensionsMixin`` is gone. + + +1.10 +==== + +No deprecations. From 539392a001888e202c5057aeca9bd08d1830b918 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 9 Jul 2014 09:32:06 +0200 Subject: [PATCH 0989/1590] AUTHORS update --- AUTHORS | 79 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0f3935d36..6319e6301 100644 --- a/AUTHORS +++ b/AUTHORS @@ -19,78 +19,79 @@ The authors of FeinCMS are: * Simon Schmid * Greg Turner * Charlie Denton -* Greg Taylor * Maarten van Gompel (proycon) * Bjarni Thorisson -* Urs Breton +* Greg Taylor * Jonas +* Urs Breton * Antoni Aloy * Julian Bez -* Marc Tamlyn -* Toby White -* Sander van Leeuwen -* Nico Echaniz * Afonso Fernández Nogueira +* Marc Tamlyn +* Martin Mahner * Max Peterson +* Nico Echaniz +* Sander van Leeuwen +* Toby White * Vítor Figueiró -* Martin Mahner -* Torkn * Andrew D. Ball -* Brian Macdonald -* Eric Delord -* Gabriel Kovacs * Maarten Draijer +* Torkn +* Gabriel Kovacs +* Eric Delord * adsworth -* Maciek Szczesniak +* Brian Macdonald +* Vaclav Klecanda +* Denis Popov +* tayg +* Wil Tan * Fabian Vogler * Fabian Germann -* Denis Popov -* Vaclav Klecanda +* Håvard Grimelid +* Marco Fucci * Raphael Jasjukaitis * Cellarosi Marco -* Wil Tan -* Michael Bashkirov * Richard A -* tayg +* Michael Bashkirov * Mikhail Korobov -* Marco Fucci -* Håvard Grimelid -* Riccardo Coroneo -* Richard Bolt +* Maciek Szczesniak * Rico Moorman -* Denis Martinez +* niklaushug * Sebastian Hillig * Silvan Spross -* David Evans -* Darryl Woods -* Daniele Procida * Artur Barseghyan * Anshuman Bhaduri * Andrin Heusser -* Sumit Datta -* Sun Liwen -* Tobias Haffner * Andrey Popelo * Andi Albrecht * Alex Kamedov -* Valtron -* Alen Mujezinovic -* Wim Feijen -* Wouter van der Graaf -* ilmarsm -* Laurent Paoletti +* Sumit Datta +* Sun Liwen +* Tobias Haffner * svleeuwen -* Livio Lunin -* Jonas Svensson +* Alen Mujezinovic +* Valtron +* George Karpenkov +* Harro van der Klauw * Jimmy Ye * Jay Yu +* Jonas Svensson +* Domas Lapinskas +* Laurent Paoletti +* Livio Lunin +* Denis Martinez +* David Evans +* Wim Feijen * Marco Cellarosi * Mark Renton -* Harro van der Klauw +* Darryl Woods +* Wouter van der Graaf * Mason Hugus -* George Karpenkov +* Daniele Procida * Mikkel Hoegh -* Domas Lapinskas +* ilmarsm * Olekasnadr Gula * Paul Garner * Piet Delport +* Riccardo Coroneo +* Richard Bolt From 8089d2724be011527f810c722f305e3fbd95610b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 9 Jul 2014 09:40:53 +0200 Subject: [PATCH 0990/1590] Switch the default rich text editor to a CDN-served version of TinyMCE 4 Also add documentation on how to activate CKEditor while at it. --- docs/contenttypes.rst | 33 +++++++++++++++++++++------------ docs/releases/1.10.rst | 9 +++++++++ example/example.db | Bin 99328 -> 105472 bytes example/models.py | 2 ++ feincms/default_settings.py | 4 ++-- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 4a45b7ae4..b57166be5 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -403,14 +403,13 @@ Rich text .. module:: feincms.content.richtext.models .. class:: RichTextContent() -Rich text editor widget, stripped down to the essentials; no media support, only -a few styles activated. The necessary javascript files are not included, +Rich text editor widget, stripped down to the essentials; no media support, +only a few styles activated. The necessary javascript files are not included, you need to put them in the right place on your own. -By default, ``RichTextContent`` expects a TinyMCE activation script at -``<MEDIA_URL>js/tiny_mce/tiny_mce.js``. This can be customized by overriding -``FEINCMS_RICHTEXT_INIT_TEMPLATE`` and ``FEINCMS_RICHTEXT_INIT_CONTEXT`` in -your ``settings.py`` file. +By default, ``RichTextContent`` uses the CDN-served version of TinyMCE 4.1. +This can be customized by overriding ``FEINCMS_RICHTEXT_INIT_TEMPLATE`` and +``FEINCMS_RICHTEXT_INIT_CONTEXT`` in your ``settings.py`` file. If you only want to provide a different path to the TinyMCE javascript file, you can do this as follows:: @@ -419,16 +418,26 @@ you can do this as follows:: 'TINYMCE_JS_URL': '/your_custom_path/tiny_mce.js', } -If you pass cleanse=True to the create_content_type invocation for your -RichTextContent types, the HTML code will be cleansed right before saving -to the database everytime the content is modified. - Additional arguments for :func:`~feincms.models.Base.create_content_type`: * ``cleanse``: - Whether the HTML code should be cleansed of all tags and attributes - which are not explicitly whitelisted. The default is ``False``. + Either the dotted python path to a function or a function itself which + accepts a HTML string and returns a cleansed version of it. A library which + is often used for this purpose is + `feincms-cleanse <https://pypi.python.org/pypi/feincms-cleanse>`_. + + +CKEditor +~~~~~~~~ + +After adding the CKEditor assets to your project, also add the following +settings:: + + FEINCMS_RICHTEXT_INIT_TEMPLATE = 'admin/content/richtext/init_ckeditor.html' + FEINCMS_RICHTEXT_INIT_CONTEXT = { + 'CKEDITOR_JS_URL': '/static/ckeditor/ckeditor.js', + } Other rich text libraries diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index 36f3a6379..79de09377 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -20,6 +20,15 @@ is that the name clash test requires the app registry to be ready (which it isn't yet when creating content types). +TinyMCE 4.1 as default rich text configuration +============================================== + +FeinCMS now uses TinyMCE 4.1 as the default rich text editor instead of the +outdated 3.x line of releases. The previous version is still officially +supported as is CKEditor. Also, the TinyMCE configuration has been changed to +hide the menubar by default. + + Backwards-incompatible changes ============================== diff --git a/example/example.db b/example/example.db index 1b42d9f2496cf90c29363ef49c9f19e3dcb77402..e1c34f7052126f9da1d4bfc0fc1fd8fbd8ed6d0e 100644 GIT binary patch delta 1228 zcmcgrO-vI}5Z>9h?QXD;6w_`EL?1=4r3G3k8q`3b)Bu(iwS*84W!YUyp_I}th6{lb z4<0x`HnA5DCLD<bvoVsGc=CWAH1Xg?6B7@{lhK3_PwLwu6-#?{lQ(%Y-+XUo=V$r8 zae3FcR%5QEC@MzI(I>9E+laCGQ-gt+%xFsoCe~A!Mq8TMR1ew{H~<~HGobFE2#3&j z-6f`(m@kO#^lJxf6-HL@sjS0|d~iuMn|{{U@doOg#g&eWlUR`#l#~#Ybw$66vq?ox zD%yzi5sj>LwaU6LaC9|VMT=;W#QXqfZH&bQB{+NyWATDI=d^0qTb_9tl1Ptg7|R;b z3-lcAYO7;zRBb>2d>}7-^U|-q60b-IQ}0!F@2U|j)DLp)+f#4XGSC6MBqwA=juzz? zI0VH>AsIUX_MTy&4R}G4ifLNQ%XdxaG&Q8M`;9O}s!`V*Y4RJWR%r7JNlYlXP?k~; zsG*JX+QWS*Q^mkM1@m+R{T6LgKJt>iXQlH7%Xf9by;F)Xo{;qtMf0L4`Lckde*A3X zj=WXRlBWuH4@biNA^)wwU?3Dx$ClE$9TA$LA{U;9$GOcZ*!GV0vwUkStO)tA(iEx5 zY;-0bOAAVTHkmnL7+1etvsC_duw#e1^R;g2-&k&J7g8xZzAL0jnbVGo?d?t+3P*5g zI2a^gQkap;qlB7>%aR>Sf+8#N8M#1p4h<N2mkUPo*=FVvanjz5JU8DVCq?;~uB#&X z@$N_fN4k500bB$+^c38L`t;W{fDI}&=tJBlW8yfPwo<eejgX10p#NuM1}mJ|#vsez z?1F56JSoWwWxE}{?3wV2KCe*LL(XLlVDlUe#Gl<P@a#Ao!uFHw+?!6YKHz}iXtY70 m*Jy*3VGT*1fPrd<4t>xMx9ZremtHeZZ-H^RYR4F*ckef`tBm>p delta 445 zcmZqJ!Pd~hHbGiYoPmKM5r|<RVWN&PP*C@gDl1S(fO!K*B6?zh!e&7pRmRO*8NV^I zW~M0VC`{hK9KylG{0$^;x0#3K1v3+?%jR$Fd<x8>jNy~nHFTKG7|j+7@-QkgFJMqq zl$I|^EiO^W%}+_qNv%lCEyzg)34r;V!!_43F^e*3PiEIq=V0z(t_4A$jrSR)nfEb> zF`{b_mu3+)WSm^6DYn^7Z?_=}^9~04$*c*DY)nZYxVa}mhgk^dFd-HmAj!kR4J6rE zxHg|kwn|}^Wz?U{e!`lK;VlSG_Bb(l@~jg)?zUnqjJk|Kg-(p(AUBqz#={-x3KZ66 z6i?1b%u7cSb^!{DFp4Lpq#%@T);oDk3ut-GWcDv=j6RbEc@(um%o%l^6Y~@x`V|lX tfnnlg?>Xw57ko)6=3ru4%)lJLv=|r))0w8LW-+dtUY5zYepwEq1OT|@e8~U+ diff --git a/example/models.py b/example/models.py index 758a0d125..629400369 100644 --- a/example/models.py +++ b/example/models.py @@ -8,6 +8,7 @@ from feincms.module.blog.models import Entry, EntryAdmin from feincms.module.page.models import Page +from feincms.content.richtext.models import RichTextContent from feincms.content.raw.models import RawContent from feincms.content.image.models import ImageContent from feincms.content.medialibrary.models import MediaFileContent @@ -26,6 +27,7 @@ ('sidebar', 'Sidebar', 'inherited'), ), }) +Page.create_content_type(RichTextContent) Page.create_content_type(RawContent) Page.create_content_type( MediaFileContent, diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 61861761b..dbe78b391 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -46,11 +46,11 @@ FEINCMS_RICHTEXT_INIT_TEMPLATE = getattr( settings, 'FEINCMS_RICHTEXT_INIT_TEMPLATE', - 'admin/content/richtext/init_tinymce.html') + 'admin/content/richtext/init_tinymce4.html') FEINCMS_RICHTEXT_INIT_CONTEXT = getattr( settings, 'FEINCMS_RICHTEXT_INIT_CONTEXT', { - 'TINYMCE_JS_URL': join(settings.MEDIA_URL, 'js/tiny_mce/tiny_mce.js'), + 'TINYMCE_JS_URL': '//tinymce.cachefly.net/4.1/tinymce.min.js', 'TINYMCE_DOMAIN': None, 'TINYMCE_CONTENT_CSS_URL': None, 'TINYMCE_LINK_LIST_URL': None From f7d5919cf88f57cd17c5500fdaeab9b249ee4958 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 9 Jul 2014 09:42:06 +0200 Subject: [PATCH 0991/1590] Remove an unused import --- feincms/default_settings.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index dbe78b391..de433a188 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -10,8 +10,6 @@ from __future__ import absolute_import, unicode_literals -from os.path import join - from django.conf import settings # ------------------------------------------------------------------------ From 59583f6bb4cdc7022af7f54dbbe48bf6bf3af218 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 9 Jul 2014 09:56:33 +0200 Subject: [PATCH 0992/1590] Run tests with Python 3.4 too --- tests/tox.ini | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/tox.ini b/tests/tox.ini index 9f7934047..98a68379c 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -15,6 +15,9 @@ envlist = py33-1.5.X, py33-1.6.X, py33-1.7.X, + py34-1.5.X, + py34-1.6.X, + py34-1.7.X, [testenv] commands = @@ -151,3 +154,33 @@ deps = feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 + +[testenv:py34-1.5.X] +basepython = python3.4 +deps = + Django==1.5.4 + django-mptt==0.6.0 + Pillow==2.4.0 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 + +[testenv:py34-1.6.X] +basepython = python3.4 +deps = + Django==1.6.0 + django-mptt==0.6.0 + Pillow==2.4.0 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 + +[testenv:py34-1.7.X] +basepython = python3.4 +deps = + https://github.com/django/django/zipball/stable/1.7.x + django-mptt==0.6.1 + Pillow==2.4.0 + feedparser==5.1.3 + lxml==3.2.3 + beautifulsoup4==4.3.1 From d7f9eddb77014c30db8ee626e6610a8148bc9bb7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 9 Jul 2014 10:55:44 +0200 Subject: [PATCH 0993/1590] Actually, now they are, sort of --- docs/contenttypes.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index b57166be5..d2df66aef 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -404,8 +404,7 @@ Rich text .. class:: RichTextContent() Rich text editor widget, stripped down to the essentials; no media support, -only a few styles activated. The necessary javascript files are not included, -you need to put them in the right place on your own. +only a few styles activated. By default, ``RichTextContent`` uses the CDN-served version of TinyMCE 4.1. This can be customized by overriding ``FEINCMS_RICHTEXT_INIT_TEMPLATE`` and From 215e3b76350e535f223701f1f897f6b279874121 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Wed, 9 Jul 2014 11:00:58 +0200 Subject: [PATCH 0994/1590] The CDN version of CKEditor would also be fine --- docs/contenttypes.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index d2df66aef..6f1078760 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -415,7 +415,7 @@ you can do this as follows:: FEINCMS_RICHTEXT_INIT_CONTEXT = { 'TINYMCE_JS_URL': '/your_custom_path/tiny_mce.js', - } + } Additional arguments for :func:`~feincms.models.Base.create_content_type`: @@ -430,12 +430,12 @@ Additional arguments for :func:`~feincms.models.Base.create_content_type`: CKEditor ~~~~~~~~ -After adding the CKEditor assets to your project, also add the following -settings:: +Add the following settings to activate `CKEditor <http://ckeditor.com/>`_:: FEINCMS_RICHTEXT_INIT_TEMPLATE = 'admin/content/richtext/init_ckeditor.html' FEINCMS_RICHTEXT_INIT_CONTEXT = { - 'CKEDITOR_JS_URL': '/static/ckeditor/ckeditor.js', + # See http://cdn.ckeditor.com/ for the latest version: + 'CKEDITOR_JS_URL': '//cdn.ckeditor.com/4.4.2/standard/ckeditor.js', } From be16a9344493eb4dada5b90f6e77a42f61b611e1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 12 Jul 2014 20:34:54 +0200 Subject: [PATCH 0995/1590] Allow deactivating check_database_schema --- feincms/default_settings.py | 6 ++++++ feincms/module/blog/models.py | 6 +++++- feincms/module/page/models.py | 5 ++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 61861761b..8f97158a2 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -106,6 +106,12 @@ # ------------------------------------------------------------------------ # Various settings +#: Run the weak replacement for a real database migration solution? +FEINCMS_CHECK_DATABASE_SCHEMA = getattr( + settings, + 'FEINCMS_CHECK_DATABASE_SCHEMA', + True) + # ------------------------------------------------------------------------ #: Allow random gunk after a valid page? FEINCMS_ALLOW_EXTRA_PATH = getattr( diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index fb578145b..7367c00b3 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -13,6 +13,7 @@ from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ +from feincms import settings from feincms.admin import item_editor from feincms.management.checker import check_database_schema from feincms.models import Base @@ -63,7 +64,10 @@ def get_absolute_url(self): return ('blog_entry_detail', (self.id,), {}) -signals.post_syncdb.connect(check_database_schema(Entry, __name__), weak=False) +if settings.FEINCMS_CHECK_DATABASE_SCHEMA: + signals.post_syncdb.connect( + check_database_schema(Entry, __name__), + weak=False) class EntryAdmin(item_editor.ItemEditor): diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index c23bf5bfe..ac475ad9e 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -430,7 +430,10 @@ class Meta: Page.register_default_processors( frontend_editing=settings.FEINCMS_FRONTEND_EDITING) -signals.post_syncdb.connect(check_database_schema(Page, __name__), weak=False) +if settings.FEINCMS_CHECK_DATABASE_SCHEMA: + signals.post_syncdb.connect( + check_database_schema(Page, __name__), + weak=False) # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ From f67344a778fe24f251f915656b1fbbd02921e497 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sat, 12 Jul 2014 20:40:47 +0200 Subject: [PATCH 0996/1590] Set FEINCMS_CHECK_DATABASE_SCHEMA to False for the upcoming 1.10 release --- docs/releases/1.10.rst | 14 ++++++++++++++ docs/settings.rst | 4 ++++ feincms/default_settings.py | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index 79de09377..d2e217960 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -29,6 +29,20 @@ supported as is CKEditor. Also, the TinyMCE configuration has been changed to hide the menubar by default. +Home-grown schema checking support has been removed +=================================================== + +Not many words needed. Use South or Django 1.7's own migrations support +instead. + +This functionality has been removed without a deprecation period because +compared to real database migration solutions it looks more like a bug than a +feature. Also, it interfered with initial migrations -- the page table's +schema was introspected because of other ``post_syncdb`` signals before the +table itself even existed under certain circumstances, which meant that +migrations failed with the only way out being ``syncdb --all``. + + Backwards-incompatible changes ============================== diff --git a/docs/settings.rst b/docs/settings.rst index f514a52f6..c85f8622a 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -139,3 +139,7 @@ Various settings ``FEINCMS_THUMBNAIL_DIR``: Defaults to ``_thumbs/``. Defines a prefix for media file thumbnails. This allows you to easily remove all thumbnails without fear of removing files belonging to image and file fields. + +``FEINCMS_CHECK_DATABASE_SCHEMA``: Defaults to ``False``. Run the home-grown +schema checker on the page module. Should not be used anymore, use South or +Django 1.7's own migrations support. diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 1350fce85..2e80f103c 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -108,7 +108,7 @@ FEINCMS_CHECK_DATABASE_SCHEMA = getattr( settings, 'FEINCMS_CHECK_DATABASE_SCHEMA', - True) + False) # ------------------------------------------------------------------------ #: Allow random gunk after a valid page? From 74037cd907006e23e6e06823147e0736d7b7ced9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 13 Jul 2014 12:58:58 +0200 Subject: [PATCH 0997/1590] FeinCMS v1.9.5 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index fe3eeaf33..6a8659b08 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 9, 4) +VERSION = (1, 9, 5) __version__ = '.'.join(map(str, VERSION)) From 146e72b8edc46a2a5cbea7ca5eea20bf38476e9c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 13 Jul 2014 13:20:04 +0200 Subject: [PATCH 0998/1590] Reword the section on database schema checking --- docs/releases/1.10.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index d2e217960..be7492239 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -29,19 +29,22 @@ supported as is CKEditor. Also, the TinyMCE configuration has been changed to hide the menubar by default. -Home-grown schema checking support has been removed -=================================================== +Home-grown schema checking support has been deactivated +======================================================= Not many words needed. Use South or Django 1.7's own migrations support instead. -This functionality has been removed without a deprecation period because +This functionality has been deactivated without a deprecation period because compared to real database migration solutions it looks more like a bug than a feature. Also, it interfered with initial migrations -- the page table's schema was introspected because of other ``post_syncdb`` signals before the table itself even existed under certain circumstances, which meant that migrations failed with the only way out being ``syncdb --all``. +To continue using this functionality, set ``FEINCMS_CHECK_DATABASE_SCHEMA`` +to ``True``. The functionality will be completely removed in the next release. + Backwards-incompatible changes ============================== From c2a818e2d14513b4e2a249b7bf228af017db34f7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 13 Jul 2014 13:22:10 +0200 Subject: [PATCH 0999/1590] Fix #505: Use of print() in management commands --- example/management/commands/generate_big_tree.py | 4 ---- feincms/management/commands/feincms_validate.py | 8 ++++---- feincms/management/commands/medialibrary_orphans.py | 4 ++-- feincms/management/commands/rebuild_mptt.py | 4 ++-- feincms/translations.py | 4 ++-- feincms/utils/queryset_transform.py | 2 +- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/example/management/commands/generate_big_tree.py b/example/management/commands/generate_big_tree.py index c3e6ddf90..3e4361c1a 100644 --- a/example/management/commands/generate_big_tree.py +++ b/example/management/commands/generate_big_tree.py @@ -2,8 +2,6 @@ # coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import print_function - from django.core.management.base import NoArgsCommand from feincms.module.page.models import Page @@ -41,5 +39,3 @@ def handle_noargs(self, **options): title='Page %s.%s.%s.%s' % (i1, i2, i3, i4), parent=parents[2], ) - - print(parents) diff --git a/feincms/management/commands/feincms_validate.py b/feincms/management/commands/feincms_validate.py index dbf681b9b..1f778d924 100644 --- a/feincms/management/commands/feincms_validate.py +++ b/feincms/management/commands/feincms_validate.py @@ -7,7 +7,7 @@ ``feincms_validate`` checks your models for common pitfalls. """ -from __future__ import absolute_import, print_function, unicode_literals +from __future__ import absolute_import, unicode_literals from django.core.management.base import NoArgsCommand from django.core.management.color import color_style @@ -22,7 +22,7 @@ class Command(NoArgsCommand): def handle_noargs(self, **options): self.style = color_style() - print("Running Django's own validation:") + self.stdout.write("Running Django's own validation:") self.validate(display_num_errors=True) for model in loading.get_models(): @@ -39,7 +39,7 @@ def validate_base_model(self, model): """ if not hasattr(model, 'template'): - print(self.style.NOTICE( + self.stdout.write(self.style.NOTICE( '%s has no template attribute; did you forget' ' register_templates or register_regions?' % model)) @@ -50,5 +50,5 @@ def validate_content_type(self, model): for base in model.__bases__: if not base._meta.abstract: - print(self.style.NOTICE( + self.stdout.write(self.style.NOTICE( 'One of %s bases, %s, is not abstract' % (model, base))) diff --git a/feincms/management/commands/medialibrary_orphans.py b/feincms/management/commands/medialibrary_orphans.py index 599c910e6..7a27a56de 100644 --- a/feincms/management/commands/medialibrary_orphans.py +++ b/feincms/management/commands/medialibrary_orphans.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import, print_function, unicode_literals +from __future__ import absolute_import, unicode_literals import os @@ -19,4 +19,4 @@ def handle_noargs(self, **options): for f in files: full = os.path.join(base[6:], f) if force_text(full) not in mediafiles: - print(os.path.join(base, f)) + self.stdout.write(os.path.join(base, f)) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index 7258bf9da..5e2b2c2cb 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -8,7 +8,7 @@ ``rebuild_mptt`` rebuilds your mptt pointers. Only use in emergencies. """ -from __future__ import absolute_import, print_function, unicode_literals +from __future__ import absolute_import, unicode_literals from django.core.management.base import NoArgsCommand @@ -21,5 +21,5 @@ class Command(NoArgsCommand): " emergencies.") def handle_noargs(self, **options): - print("Rebuilding MPTT pointers for Page") + self.stdout.write("Rebuilding MPTT pointers for Page") Page._tree_manager.rebuild() diff --git a/feincms/translations.py b/feincms/translations.py index 82c761bea..f7df973fb 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -18,14 +18,14 @@ class NewsTranslation(Translation(News)): available) or in any other language:: for news in News.objects.all(): - print news.translation.title + print(news.translation.title) Print all the titles of all news entries which have an english translation:: from django.utils import translation translation.activate('en') for news in News.objects.filter(translations__language_code='en'): - print news.translation.title + print(news.translation.title) """ from __future__ import absolute_import, unicode_literals diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 0e26092ab..c6acf4a31 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -31,7 +31,7 @@ def lookup_tags(item_qs): qs = Item.objects.filter(name__contains = 'e').transform(lookup_tags) for item in qs: - print item, item.fetched_tags + print(item, item.fetched_tags) Prints:: From 1a6c8d9189c6acc6c4c69562e1e045ee1a413723 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 20 Jul 2014 14:46:15 +0200 Subject: [PATCH 1000/1590] Add a new page extension for distinguishing between different navigation groups --- docs/page.rst | 17 +++++--- docs/releases/1.10.rst | 18 ++++++++ docs/templatetags.rst | 11 +++++ .../page/extensions/navigationgroups.py | 37 ++++++++++++++++ .../page/templatetags/feincms_page_tags.py | 11 ++++- tests/testapp/models.py | 1 + tests/testapp/tests/test_page.py | 43 +++++++++++++++++++ 7 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 feincms/module/page/extensions/navigationgroups.py diff --git a/docs/page.rst b/docs/page.rst index 513be9f1d..5ddd3f24e 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -40,9 +40,9 @@ by adding the following lines somewhere into your project, for example in a from feincms.content.medialibrary.models import MediaFileContent Page.register_extensions( - 'feincms.module.extensions.datepublisher', + 'feincms.module.extensions.datepublisher', 'feincms.module.extensions.translations' - ) # Example set of extensions + ) # Example set of extensions Page.register_templates({ 'title': _('Standard template'), @@ -50,14 +50,14 @@ by adding the following lines somewhere into your project, for example in a 'regions': ( ('main', _('Main content area')), ('sidebar', _('Sidebar'), 'inherited'), - ), - }) + ), + }) Page.create_content_type(RichTextContent) Page.create_content_type(MediaFileContent, TYPE_CHOICES=( ('default', _('default')), ('lightbox', _('lightbox')), - )) + )) It will be a good idea most of the time to register the @@ -202,6 +202,13 @@ The following extensions are available currently: this extension. +* :mod:`feincms.module.page.extensions.navigationgroups` --- Navigation groups + + Adds a navigation group field to each page which can be used to distinguish + between the header and footer (or meta) navigation. Filtering is achieved + by passing the ``group`` argument to ``feincms_nav``. + + * :mod:`feincms.module.page.extensions.relatedpages` --- Links related content Add a many-to-many relationship field to relate this page to other pages. diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index be7492239..15df9431c 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -46,6 +46,24 @@ To continue using this functionality, set ``FEINCMS_CHECK_DATABASE_SCHEMA`` to ``True``. The functionality will be completely removed in the next release. +A better mechanism for assigning pages to different menu bars +============================================================= + +The new extension :mod:`feincms.module.page.extensions.navigationgroups` +allows assigning pages to different regions, and asking ``feincms_nav`` to +only return pages belonging to one of those. + +The default configuration of the extension defines two regions, ``default`` +and ``footer``. This can be easily changed by subclassing the extension class +and overriding the ``groups`` attribute and registering this extension class +instead of the original. + +An example for getting a list of pages for the footer region follows:: + + {% load feincms_page_tags %} + {% feincms_nav feincms_page level=2 group='footer' as footer_nav %} + + Backwards-incompatible changes ============================== diff --git a/docs/templatetags.rst b/docs/templatetags.rst index 203168b87..bb008207c 100644 --- a/docs/templatetags.rst +++ b/docs/templatetags.rst @@ -72,6 +72,7 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: level: 1 = toplevel, 2 = sublevel, 3 = sub-sublevel depth: 1 = only one level, 2 = subpages too + group: Only used with the ``navigationgroups`` extension If you set depth to something else than 1, you might want to look into the ``tree_info`` template tag from the mptt_tags library. @@ -85,6 +86,16 @@ All page module-specific template tags are contained in ``feincms_page_tags``:: <a href="{{ p.get_absolute_url }}">{{ p.title }}</a> {% endfor %} + Example for outputting only the footer navigation when using the + default configuration of the ``navigationgroups`` page extension:: + + {% load feincms_page_tags %} + + {% feincms_nav feincms_page level=2 depth=1 group='footer' as meta %} + {% for p in sublevel %} + <a href="{{ p.get_absolute_url }}">{{ p.title }}</a> + {% endfor %} + .. function:: siblings_along_path_to: This is a filter designed to work in close conjunction with the diff --git a/feincms/module/page/extensions/navigationgroups.py b/feincms/module/page/extensions/navigationgroups.py new file mode 100644 index 000000000..f56e2513a --- /dev/null +++ b/feincms/module/page/extensions/navigationgroups.py @@ -0,0 +1,37 @@ +""" +Page navigation groups allow assigning pages to differing navigation lists +such as header, footer and what else. +""" + +from __future__ import absolute_import, unicode_literals + +from django.db import models +from django.utils import six +from django.utils.translation import ugettext_lazy as _ + +from feincms import extensions +from feincms.utils import get_object +from feincms._internal import monkeypatch_method + + +class Extension(extensions.Extension): + ident = 'navigationgroups' + groups = [ + ('default', _('Default')), + ('footer', _('Footer')), + ] + + def handle_model(self): + self.model.add_to_class( + 'navigation_group', + models.CharField( + _('navigation group'), + choices=self.groups, + default=self.groups[0][0], + max_length=20, + db_index=True)) + + def handle_modeladmin(self, modeladmin): + modeladmin.add_extension_options(['navigation_group']) + modeladmin.extend_list('list_display', ['navigation_group']) + modeladmin.extend_list('list_filter', ['navigation_group']) diff --git a/feincms/module/page/templatetags/feincms_page_tags.py b/feincms/module/page/templatetags/feincms_page_tags.py index 07552077a..b9cbdd520 100644 --- a/feincms/module/page/templatetags/feincms_page_tags.py +++ b/feincms/module/page/templatetags/feincms_page_tags.py @@ -40,7 +40,7 @@ def format_exception(e): # ------------------------------------------------------------------------ @register.assignment_tag(takes_context=True) -def feincms_nav(context, feincms_page, level=1, depth=1): +def feincms_nav(context, feincms_page, level=1, depth=1, group=None): """ Saves a list of pages into the given context variable. """ @@ -152,6 +152,15 @@ def _navext_filter(iterable): queryset = _navext_filter(queryset) + if group is not None: + # navigationgroups extension support + def _navigationgroup_filter(iterable): + for elem in iterable: + if getattr(elem, 'navigation_group', None) == group: + yield elem + + queryset = _navigationgroup_filter(queryset) + # Return a list, not a generator so that it can be consumed # several times in a template. return list(queryset) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 24918168a..011ae1192 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -123,6 +123,7 @@ def children(self, page, **kwargs): 'feincms.module.page.extensions.navigation', 'feincms.module.page.extensions.symlinks', 'feincms.module.page.extensions.titles', + 'feincms.module.page.extensions.navigationgroups', ) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index ab4e7ebe0..56797cebc 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -88,6 +88,7 @@ def create_page_through_admin(self, title='Test page', parent='', 'initial-publication_date_0': '2009-01-01', 'initial-publication_date_1': '00:00:00', 'language': 'en', + 'navigation_group': 'default', 'site': self.site_1.id, 'rawcontent_set-TOTAL_FORMS': 0, @@ -128,6 +129,7 @@ def create_page(self, title='Test page', parent=None, **kwargs): 'site': self.site_1, 'in_navigation': False, 'active': False, + 'navigation_group': 'default', } defaults.update(kwargs) return Page.objects.create( @@ -349,6 +351,7 @@ def create_page_through_admincontent(self, page, **kwargs): 'initial-publication_date_0': '2009-01-01', 'initial-publication_date_1': '00:00:00', 'language': 'en', + 'navigation_group': 'default', 'site': self.site_1.id, 'rawcontent_set-TOTAL_FORMS': 1, @@ -1730,3 +1733,43 @@ def test_38_invalid_template(self): page = Page() page.template_key = 'test' self.assertEqual(page.template.key, 'base') + + def test_39_navigationgroups(self): + self.create_default_page_set() + + page1, page2 = list(Page.objects.order_by('id')) + + page1.active = True + page1.in_navigation = True + page1.save() + + page2.active = True + page2.in_navigation = True + page2.navigation_group = 'footer' + page2.save() + + t = template.Template( + ''' +{% load feincms_page_tags %} +{% feincms_nav feincms_page level=1 depth=10 group='default' as nav %} +{% for p in nav %}{{ p.get_absolute_url }},{% endfor %} + ''' + ) + str = t.render(template.Context({ + 'feincms_page': page1, + })) + + self.assertEqual(str.strip(), '/test-page/,') + + t = template.Template( + ''' +{% load feincms_page_tags %} +{% feincms_nav feincms_page level=1 depth=10 group='footer' as nav %} +{% for p in nav %}{{ p.get_absolute_url }},{% endfor %} + ''' + ) + str = t.render(template.Context({ + 'feincms_page': page1, + })) + + self.assertEqual(str.strip(), '/test-page/test-child-page/,') From 7721969912909c1ec7e8ef7ae80a68aa5594a96f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 20 Jul 2014 15:00:02 +0200 Subject: [PATCH 1001/1590] i18n --- feincms/locale/ca/LC_MESSAGES/django.po | 702 +++++++++++--------- feincms/locale/cs/LC_MESSAGES/django.po | 649 +++++++++--------- feincms/locale/de/LC_MESSAGES/django.mo | Bin 15382 -> 16573 bytes feincms/locale/de/LC_MESSAGES/django.po | 719 +++++++++++--------- feincms/locale/en/LC_MESSAGES/django.po | 576 ++++++++-------- feincms/locale/es/LC_MESSAGES/django.po | 701 +++++++++++--------- feincms/locale/fr/LC_MESSAGES/django.po | 702 +++++++++++--------- feincms/locale/hr/LC_MESSAGES/django.po | 708 +++++++++++--------- feincms/locale/it/LC_MESSAGES/django.po | 697 +++++++++++--------- feincms/locale/nb/LC_MESSAGES/django.po | 699 +++++++++++--------- feincms/locale/nl/LC_MESSAGES/django.po | 730 ++++++++++++--------- feincms/locale/pl/LC_MESSAGES/django.po | 681 ++++++++++--------- feincms/locale/pt/LC_MESSAGES/django.po | 729 +++++++++++--------- feincms/locale/pt_BR/LC_MESSAGES/django.po | 725 +++++++++++--------- feincms/locale/ro/LC_MESSAGES/django.po | 699 +++++++++++--------- feincms/locale/ru/LC_MESSAGES/django.po | 342 +++++----- feincms/locale/tr/LC_MESSAGES/django.po | 715 +++++++++++--------- feincms/locale/zh_CN/LC_MESSAGES/django.po | 693 ++++++++++--------- 18 files changed, 6262 insertions(+), 5205 deletions(-) diff --git a/feincms/locale/ca/LC_MESSAGES/django.po b/feincms/locale/ca/LC_MESSAGES/django.po index 645d74bc3..d415b080b 100644 --- a/feincms/locale/ca/LC_MESSAGES/django.po +++ b/feincms/locale/ca/LC_MESSAGES/django.po @@ -1,744 +1,775 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # proycon <proycon@anaproy.nl>, 2009 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Catalan (http://www.transifex.com/projects/p/feincms/language/ca/)\n" +"Language-Team: Catalan (http://www.transifex.com/projects/p/feincms/language/" +"ca/)\n" +"Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "plantilla" - -#: models.py:510 -msgid "ordering" -msgstr "ordenació" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "idioma" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Tots" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Pare" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "títol" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s ha sigut mogut a una nova posició" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "No entenc l'odre de moviment" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "accions" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "contingut de l'aplicació" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "continguts de l'aplicació" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplicació" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "actiu" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Es podran afegir nous comentaris" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "comentaris" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "públic" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "privat" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nom" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "correu" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "assumpte" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "contingut" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "formulari de contacte" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "formularis de contacte" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "arxiu" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "arxius" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "imatge" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "llegenda" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "imatges" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "posició" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "arxiu de medis" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "arxius de medis" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tipus" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "contingut en cruu" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "continguts en cruu" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Ignora els avisos de validació de l'HTML" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "La validació de l'HTML generà %(count)d avisos. Per favor, revisa el contingut actualitzat de la part inferior abans de continuar: %(messages)s" +msgstr "" +"La validació de l'HTML generà %(count)d avisos. Per favor, revisa el " +"contingut actualitzat de la part inferior abans de continuar: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "text" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "text ric" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "texts rics" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "El feed RSS s'actualitza varies vegades al dia. Els canvis en el títol sols seran visibles a la plana inicial després de la propera actualització." +msgstr "" +"El feed RSS s'actualitza varies vegades al dia. Els canvis en el títol sols " +"seran visibles a la plana inicial després de la propera actualització." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "enlaç" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "contingut pre-renderitzat" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "darrera actualització" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "nombre màxim" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "feed RSS" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "feeds RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "secció" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "seccions" -#: content/table/models.py:63 -msgid "plain" -msgstr "plà" - -#: content/table/models.py:64 -msgid "title row" -msgstr "títol de la fila" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "títol de fila i columna" - -#: content/table/models.py:72 -msgid "table" -msgstr "taula" - -#: content/table/models.py:73 -msgid "tables" -msgstr "taules" - -#: content/table/models.py:87 -msgid "data" -msgstr "dades" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "plantilla de contingut" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "plantilles de continguts" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "plantilla" + +#: content/video/models.py:34 msgid "video link" msgstr "enllaç de vídeo" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Això ha de ser un enllaç a un vídeo de Youtube o Vimeo. Per exemple: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Això ha de ser un enllaç a un vídeo de Youtube o Vimeo. Per exemple: http://" +"www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "vídeo" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "vídeos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "ordenació" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "etiquetes" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "idioma" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "tradució de" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Deixa aquest camp buid per les entrades en l'idioma base" + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "traduccions disponibles" + +#: module/blog/models.py:33 msgid "published" msgstr "publicat" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Això també es fa servir per la navegació generada automàticament." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publicat el" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "S'establirà automàticament quan marquis la casella superior de 'publicat'" +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"S'establirà automàticament quan marquis la casella superior de 'publicat'" -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "entrada" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "entrades" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "etiquetes" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "tradució de" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Deixa aquest camp buid per les entrades en l'idioma base" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "traduccions disponibles" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "data de creació" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "data de modificació" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "tipus de contingut" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "data de publicació" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "publicar fins a" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Si la deixen en blanc l'entrada estarà activa per sempre" -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "visible de-fins a" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Publicació segons la data" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "categoritzat" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Categoritzat" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta paraules" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Això serà afegit a la llista de paraules clau per defecte" +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta descripció" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Això serà afegit a la descripció per defecte" +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Optimització per als motors de cerca" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Editar la traducció" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Crear traducció" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "traduccions" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Previsualitzar" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "tamany d'arxiu" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "creat" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "tipus d'arxiu" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "informació de l'arxiu" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "pare" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "categories" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "drets de còpia" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Imatge" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "document PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Text" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Text ric" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binari" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "descripció" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "traducció de l'arxiu de medis" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "traduccions dels arxius de medis" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "extracte" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Afegeix una breu descripció resumint el contingut de la plana" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Extracte" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "extensió de navegació" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Selecciona el mòdul que proveeix les subplanes si necessites personalitzar " +"la navegació." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Extensió de navegació" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "a la navegació" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Selecciones les planes que es mostraran com a contingut relacionat." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Planes relacionades" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "Plana enllaçada" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Tot el contingut es heretat d'aquesta plana." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "títol del contingut" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "La primera línia és el títol principal, les altres són subtítols." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "títol de la plana" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "Títol de la plana pel navegador. Per defecte el mateix que el títol." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Títols" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Aquesta URL ja està en ús en una plana activa." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Aquesta URL ja età en ús per una altra plana activa." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Altres opcions" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "a la navegació" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Afegeix una plana filla." -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Veure a Lloc" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "heretat" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "extensions" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "és activa" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "actiu" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Això també es fa servir per la navegació generada automàticament." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "URL sobrescrit" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Sobreescriu l'URL. Ha de contenir una '/' a l'inici i al final quan es tracti d'una URL local. Afecta tant a la navegació com a les URLs de les subplanes." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Sobreescriu l'URL. Ha de contenir una '/' a l'inici i al final quan es " +"tracti d'una URL local. Afecta tant a la navegació com a les URLs de les " +"subplanes." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "redirecciona a" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "URL en caché" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "plana" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "planes" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "extracte" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Afegeix una breu descripció resumint el contingut de la plana" - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Extracte" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "extensió de navegació" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Selecciona el mòdul que proveeix les subplanes si necessites personalitzar la navegació." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Extensió de navegació" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Selecciones les planes que es mostraran com a contingut relacionat." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Planes relacionades" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "Plana enllaçada" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Tot el contingut es heretat d'aquesta plana." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "títol del contingut" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "La primera línia és el títol principal, les altres són subtítols." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "títol de la plana" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Títol de la plana pel navegador. Per defecte el mateix que el títol." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Títols" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "Per %(filter_title)s" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Segur que vols esborrar l'element?" @@ -757,7 +788,8 @@ msgstr "Impossible esborrar l'element" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "No puc esborrar l'element ja que és el pare d'almanco un altre element." +msgstr "" +"No puc esborrar l'element ja que és el pare d'almanco un altre element." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -770,9 +802,8 @@ msgstr "Vols canviar la plantilla?<br /> Tots els canvis es guardaran." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -807,22 +838,24 @@ msgstr "Regió buida" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "El contingut de la plana pare s'inserirà automàticament. Per sobreescriure aquest comportament afegeix algun contingut." +msgstr "" +"El contingut de la plana pare s'inserirà automàticament. Per sobreescriure " +"aquest comportament afegeix algun contingut." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Afegir un nou element" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Guardar" @@ -850,13 +883,21 @@ msgstr "avall" msgid "remove" msgstr "esborrar" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Editar al Lloc" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Inici" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -879,29 +920,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Dreceres" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Tancar l'arbre" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Expandir l'arbre" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Editar al Lloc" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Per %(filter_title)s" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -945,9 +983,13 @@ msgstr "%(comment_count)s comentaris." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s digué el %(comment_submit_date)s<br />\n" " " -msgstr "\n %(comment_username)s digué el %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -964,3 +1006,27 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Gràcies!" + +#~ msgid "plain" +#~ msgstr "plà" + +#~ msgid "title row" +#~ msgstr "títol de la fila" + +#~ msgid "title row and column" +#~ msgstr "títol de fila i columna" + +#~ msgid "table" +#~ msgstr "taula" + +#~ msgid "tables" +#~ msgstr "taules" + +#~ msgid "data" +#~ msgstr "dades" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Això serà afegit a la llista de paraules clau per defecte" + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Això serà afegit a la descripció per defecte" diff --git a/feincms/locale/cs/LC_MESSAGES/django.po b/feincms/locale/cs/LC_MESSAGES/django.po index a099e2384..fea739112 100644 --- a/feincms/locale/cs/LC_MESSAGES/django.po +++ b/feincms/locale/cs/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,193 +17,191 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "šablona" - -#: models.py:510 -msgid "ordering" -msgstr "řazení" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "jazyk" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "vše" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "rodič" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "kategorie" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "změň %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "Název" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +#, fuzzy +#| msgid "You don't have the necessary permissions to edit this object" +msgid "You do not have permission to modify this object" +msgstr "Nemáte dostatečná oprávnění pro editaci tohoto objektu" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s přesunut na novou pozici" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Nesrozumitelné přesunutí" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "akce" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." -msgstr "" +#: admin/tree_editor.py:552 +#, fuzzy, python-format +#| msgid "Successfully added %(count)d media file to %(category)s." +#| msgid_plural "Successfully added %(count)d media files to %(category)s." +msgid "Successfully deleted %(count)d items." +msgstr "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, fuzzy, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "Obnov smazané %(verbose_name)s" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "aplikační obsah" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "aplikační obsahy" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplikace" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "zapnutý" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Komentáře povoleny" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "komentáře" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "veřejný" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "neveřejný" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "jméno" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "předmět" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "obsah" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "kontaktní formulář" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "kontaktní formuláře" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "soubor" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "soubory" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "obrázek" -#: content/image/models.py:48 +#: content/image/models.py:49 #, fuzzy msgid "alternate text" msgstr "šablonový obsah" -#: content/image/models.py:49 +#: content/image/models.py:50 #, fuzzy msgid "Description of image" msgstr "popis" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "název" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "obrázky" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "pozice" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "mediální soubor" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "mediální soubory" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "typ" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "binární obsah" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "binární obsahy" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "čisté HTML " -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "ignorovat HTML validační varovnání" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " @@ -212,19 +210,19 @@ msgstr "" "HTML validace vyplivla %(count)d varování. Prosím zkontroluj obsah níže před " "pokračováním: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "text" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." @@ -232,75 +230,55 @@ msgstr "" "RSS pole je měněno několikrát za den. Změna v titulku bude patrná při přístí " "změně RSS kanálu." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "odkaz" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "predrenderovaný obsah" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "naposledy změněno" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "max. položek" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS kanál" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "RSS kanály" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "sekce" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "sekce" -#: content/table/models.py:63 -msgid "plain" -msgstr "prostý" - -#: content/table/models.py:64 -msgid "title row" -msgstr "titulní řádka" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "titulní řádka a sloupec" - -#: content/table/models.py:72 -msgid "table" -msgstr "tabulka" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tabulky" - -#: content/table/models.py:87 -msgid "data" -msgstr "" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "šablonový obsah" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "šablonové obsahy" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "šablona" + +#: content/video/models.py:34 msgid "video link" msgstr "odkaz na video" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" "This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." "com/watch?v=zmj1rpzDRZ0" @@ -308,139 +286,150 @@ msgstr "" "Toto má být odkaz na youtube nebo vimeo video, např. http://www.youtube.com/" "watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "videoa" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "Tagy" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "řazení" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "tagy" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "jazyk" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "překlad" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Nech prázdné pro články v primárním jazyce" + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "překlady k dispozici" + +#: module/blog/models.py:33 msgid "published" msgstr "publikovaný" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Toto je také použito pro generovanou navigaci" -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publikovaný" -#: module/blog/models.py:34 +#: module/blog/models.py:42 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" "Bude automaticky nastaven jakmile klikneš na zaškrtávátko `publikovaný` výše." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "Článek" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "Články" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "tagy" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "překlad" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Nech prázdné pro články v primárním jazyce" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "překlady k dispozici" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "datum vytvoření" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "datum úpravy" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "typy obsahu" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "datum publikace" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "konec publikace" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Nech prázdné pro články, které mají být publikovány stále" -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "Publikováno od - do" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Publikování na základě data" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "zvýrazněný" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "zvýrazněný" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta klíčová slova" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Toto bude přidáno k výchozím klíčovým slovům" +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta popis" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Toto bude přidáno k výchozímu popisu" +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Optimalizace pro vyhledávače" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Vytvoř překlad" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "překlady" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " @@ -449,207 +438,308 @@ msgstr "" "Nemůže být přepsán jiným typem (pokoušíš se přepsat %(old_ext)s s " "%(new_ext)s)" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." msgstr[1] "Úspěšně přidáno %(count)d mediálních souborů do %(category)s." -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "Přiděj vybrané mediální soubory do kategorie" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "ZIP archiv exporotován jako %s" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "export ZIP archivu selhal: %s" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "Vyexportuj vybrané mediální soubory jako zip archiv" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "náhled" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "velikost souboru" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "vytvoreno" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "typ souboru" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "info o souboru" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "%d souborů importováno" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "import ZIPu selhal: %s" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "Žádný vstupní soubor" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "rodič" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "kategorie" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "kategorie" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "obrázek" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF dokument" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binární" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "popis" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "překlad mediálního souboru" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "překlady mediálního souboru" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "výňatek" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "rozšíření navigace" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Vyber modul nabízející podstránky pro tuto stránku jestli chceš upravit " +"navigaci." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "rozšíření navigace" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "v navigaci" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Vyber příbuzné stránky" + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Příbuzné stránky" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "propojená stránka" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Všechen obsah je poděděn do této stránky, pakliže vybrána" + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "Název obsahu" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "První řádka je hlavní titulek, ostatní řádky podtitulky" + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "titulek stránky" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "Titulek pro okno prohlížeče. Výchozí: stejné jako titulek stránky." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Titulky" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Toto URL je už obsazeno aktivní stránkou." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Toto URL je už obsazeno jinou stránkou." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Další nastavení" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "v navigaci" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Přidej podřízenou stránku" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Zobrazena na sajtě." -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "Originálnío překlad zkopírován do nově vytvořené stránky." -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "Nemáte dostatečná oprávnění pro editaci tohoto objektu" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "zděděný" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "rozšíření" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "je aktivní" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "aktivní" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Toto je také použito pro generovanou navigaci" + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "vynucené URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " "the end if it is a local URL. This affects both the navigation and subpages' " @@ -658,101 +748,34 @@ msgstr "" "Přepíše cílové URL. Ujisti se, že máš \"/\" na začátku a na konci pro " "lokální URL.Toto ovlivňuje navigaci cílové stránky i podstránek" -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "přesměruj na" -#: module/page/models.py:178 +#: module/page/models.py:193 #, fuzzy msgid "Target URL for automatic redirects or the primary key of a page." msgstr "Cílová adresa pro automatické přeměrování" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "stránka" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "stránky" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "výňatek" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "rozšíření navigace" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "" -"Vyber modul nabízející podstránky pro tuto stránku jestli chceš upravit " -"navigaci." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "rozšíření navigace" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Vyber příbuzné stránky" - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Příbuzné stránky" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "propojená stránka" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Všechen obsah je poděděn do této stránky, pakliže vybrána" - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "Název obsahu" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "První řádka je hlavní titulek, ostatní řádky podtitulky" - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "titulek stránky" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Titulek pro okno prohlížeče. Výchozí: stejné jako titulek stránky." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Titulky" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "" @@ -831,16 +854,16 @@ msgstr "" msgid "Add new item" msgstr "Přidej novou položku" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "Přidej nové %(verbose_name)s" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "Smaž" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Ulož" @@ -868,13 +891,21 @@ msgstr "dolů" msgid "remove" msgstr "odeber" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Edituj přímo na webu" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Domů" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Přidej" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -897,29 +928,26 @@ msgstr "Revertuj %(verbose_name)s" msgid "Press the save button below to revert to this version of the object." msgstr "Zmáčkni tlačítko ulož níže pro revertování na tuto verzi objektu." -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Zkratky" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Rozbal strom" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Zabal strom" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtruj" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Edituj přímo na webu" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Přidej" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -984,6 +1012,27 @@ msgstr "Odeslat" msgid "Thanks!" msgstr "Díky!" +#~ msgid "plain" +#~ msgstr "prostý" + +#~ msgid "title row" +#~ msgstr "titulní řádka" + +#~ msgid "title row and column" +#~ msgstr "titulní řádka a sloupec" + +#~ msgid "table" +#~ msgstr "tabulka" + +#~ msgid "tables" +#~ msgstr "tabulky" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Toto bude přidáno k výchozím klíčovým slovům" + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Toto bude přidáno k výchozímu popisu" + #~ msgid "(no caption)" #~ msgstr "(bez názvu)" diff --git a/feincms/locale/de/LC_MESSAGES/django.mo b/feincms/locale/de/LC_MESSAGES/django.mo index deda58df15ab1ad566239c7d02f504aaba3f9d26..0c21f5ae348b875f90e6a87800953f27a0674216 100644 GIT binary patch delta 6479 zcmbW4d3aUD8HZ0~(F7C(L8ua@5rRO70m2qqfv|?XB#43vC%Gp#7jEv2=blRdTdrVR zYwJRLSt?dh>H>AGx6~?#OKRP)7OPmTEmWVn_0ig@)joE6f9DL#)Be|a_?`EgIcH|R z`M#OCVe6VlHWcN4->dT$hjIj+EuHK*ql@5aR4DKCa-0?LUDyZC?(H~d!4>dy_*FOv zUI#nD0vrY(gcIN!FdX*`$I*}zp!&~(-5n?A#4t3#Wv~a_3cJ8Npa#4fj)eEy_BUWx z>hD<o8J<b~Z?FWOhL?KZAL6rP;50ZIx^N9V1-=H0ncsO6LleIbPlf-4ePK5q&9DrX z!mFVM+y(i>*$WAla}W-JuR?rqitwf!_Jyp_`7-PYXG49z40eM}a0v4|X$*O^4a)Od zpdxUmt=|KSss989a6jw}NB4^c91m5W49|hnq53DFCQ8FEz{_C;+zP8<2h5GZ_zXi4 zsO%rD;C!fD)!TX_<e$^dLo50&B(2WPP!W5;@-cWb^<P3c+{&!_z8zi)zYev)H*NcS zUm*UqG<-^fa#X|4P>6C+5xEL#piOW)+z#dW7<QB#SP2bW4>i#aD2MKbn&@Fju$;%C z#(5PgQg1@0bly3e_~We8X@KL5g#+L+*Z}q6{ZJkE*!rWEKZly|8K{X4K_C7OY5@z` zFq7ehP~+SH)qXQ<fOkMG`12gb6pYCO9p@WxBaFdQOq8ousNKIER>A{tIQ$%rf<wN@ zMuJP>HE=&v`<ybz84A}!Ik*dIPuvIP_#QYD=AOW)!YE<qd<jm33e6g*(B+|a`(03* z>2au)JP$SS%TRmeb^HELP^tM8o&mcJicXV(>NgJRm`;MEIOoic45uE-vx}i}n1Jfg zZtFSAYoStdqkVt7ZNCS~!M(6Ee9H0w)XEP+jrWS>;jo?jzik`dhw|(bsLkgLjs_}* zn(#EsewJmh3+)w9kr-v`6Ks7F)Iw%J^>47e6l(ky*q!;E%P=~_^-vC6X?Y#wPH}F4 zO2z$9D|{O2LU{>lf<HoC#UDY9)1^ELeF@Ze17Rmv1vP#(lmnAsP9dL#p^l5~2TNfW z>K^P0S3z~~p>le;ZQlen!8Y5z3u>j0K#ltpl*2FC`Vm`yA9khv@8#rQ9dv)nvl6Hr z^?{mj0F-0pwtYC%W*cqWYoWfI3FXK_s7Sc>eFkbFYoPkAhjQ#%`+mFb-;-$AVL#jn z<;X554+~HOJ`8Uv;`qVysjnOwrDQkc$UBciosz?F82kik<%WuG*a}FK(+J6ua}88# zAIM=44d)rCi|9i*8kP)q9ByUje0VZk0u_nna5juVt?WK1NB6*Pa37RIPeb*83l_tF zLoQFJxPspYI2f*gxm6hY-~cRvhoD0F2dLkKzd{!6oHQc3n1(^_DCc^p72F36`~_4h z-iG{hKIG92mU3%x$2r5GHgO%)LS2aCIp=Z=O}G*23eH2V_}S<K=S8TMz6#~&Vas>n zmDE3ia=iV#sNY7Y`nRD%y#*?Ad*NyDF(`*#fa96p`2a&X8dAk?HM|7&fHy+z_Pb!% z5o!f5K%(iq4YfCVkBlNQ80znXFTtL00o(;wK=m)?UhWS2K_3o=r|SHFA43z}0cXIy zmM5_h6w*4&MNkn~2JeO*R4#i}M_2ZRkn7*cK!tt_lq0u7^?Lwn<@=x_@>`fwsE=T1 zv%CYfi;D=yEO;iI0#`t7vYk+o*$w5`Lr|%C0-g?^hWhR`xB>nFYWybhIuEXbn)o58 z@Ai)+{yI)i(ohRKkBdH>3G>vqz$6?xK1$J6s1zN5{BuesM0;i`RIb;-6ubpq4|~)^ zKf^oVMCwPN96p<hST>RP_s2MwhDop%YULX(pMyG1XYkX=-we(usQLn^P1Xt(i8W9I zZh*@5RZuC|YPl1hO8s7_U)Oz5k$EMDp@9xV<>)<I{}?LN|Axw850<Tv8K_M(#IhQy z-xMfE=0Hu{VBfER>emW2PhjggsD8O`T4NKGN89ZOJE1(@ZQCD&TH&Km9iN19<OQgS zUx(`dN2m$khsyQGw*Ggh@04%7FNTblb9!Q^V_(<@mO^!`hKj%hs1?=0esD2V2vblF zUJbSRw%Ph_%Lk#xc@pZ_J`45T8&JQ7ABT1F{~3ltQ^E%54f{Z?bSTus=RtWq5o*F( zsFf^)ec?q=j<!Mdzru2}ZQliZ(f%{2d7gtB_mJM_Fy6pWNdF4u@jsv(D4HBa=47b% zJ)qwAhl*G!)ZQqEa%i08WXn3Jev6>`T?{p@3)L?UbK0$IFcgxjpg#N#)Q6j(Jl+Zw zfm`7ja2G6sOVC2}D7qKvmsBN=riE7Y7z{FqQ+cf1g*8k0zX5~2ajXPbub^{n%g-!z zuAjE{QRs3?*vgMBZ?)9@@eK0OH_%peGkO833<;mP@EKmCTQDo4YIrATv-|?BKsyn4 zRJcK(fGUd6JaiALLQf%;8E7}U8hr=tLN0m?sXQLRX@T4A{LT?7JJ6-*98{0KhE$r- z{?Ow0-|{Gag3*Lx=-24Ch)XUkKj+B>8kYMkh2Nut=n9nk5syh|F?tB8d>8!&{XiAU zH_<IJD5Yp_Xhn}r*4}eMTP=3u33U%UjW(j|(d$TsyDb;q?>(q|3vEN%nFUmg4kH~M zl~yzdWmTbEi7rI*kv8R5(A{V=(*3XwosCo;Mz@Dn^mq+)LSJS6@XswZU#thE4V5E< zR63(GLyLPKu0=XEDwm@NLo0glbKyLX9zZ`u=OdNhp;4j5eFD!y7oke#cb-HlFQG4@ zfoLYW3N1o+qU(@~E}Y9yH5!2~K`KMh$*2L1L@LW7gip=$B3gxpqsd4m_kAAMhGz7* zz}h<ZhpfFG-iS8X`mZe8;Zk%H>WaRHRQ90*p~Zh%;MY-|tq+4^&^2hb@;?aU5%e-z ziB$GRh<-4zyQ5caTR(W4wZ9E}TYC+B7M+Tovuz!)8!AJ;MB~u_v>HuCKMdbusN9ji zq}QSH!RIF3R6Og(y`dQs_--nbbb~}XWzx;2Z1A~l;fu0DW$)c54M?}GHBISM;H3i7 z?5A5z(Bhf2pNJ<?ZZiLJpNcNcZZ;X@|JCQ^t~1i<!1MDj_I-2s9B*xV+K*+7>w6{< zPo;e?W*XO;)^sK?8PD~bT8x)s5HFK2ocWjT^V6oy^IH>{Od_4%+3%Cem=}&)Y360= zkxB=q(KE?(D(?BX;HJ#DD$~^B`fd|bW(qs{r#sDRaN~>^cN$zj?geJ?qPeCy?He~6 zq+3~Flfj9E?==M(RuC?v%}=zt{#vujTdT#pMr*GuR1e4&Esp}Ryea8sGQ=sH@mP(? zFhSA_2v*>=wh=e4!nmoJnK8X?{?vK(%j@gr&zw8GVZr?64b$f>oI9mq`toVhX{e)R z%G|jNmQ0`a<r!`=<K=%<YVsYW!9|I1?3fACrZJmHVi4h@z6UM5mQzl{QOm^Ac%q27 z$z;0SxIy4HwX`ZhETO4IL#Rh4KXTy8T;Qz<3}eI+8N6Lf7UViJ*d+K~hV(^qRGPZ* z+m>{@x0*O>4wfAYqo_Xh(-#=F%PL|}X&N;0i5VGLePT*9Y2epnQ%%GuRvGypB!VRS zfj}lR>EmOk+|`MAv;|p5)+C5+Cja@s&BH<;THMv%@$G^8Y4%Yp(Y%(0Fjl&8B{?m8 z%WNzv^eBrJ^*BCS+)roQ@|T@6Ex-4igZUc<P0W8ZC^x8N;ev({Q++R-al|zIt1+Xh zMplog8aHB8l^I!GGiE}5|KL5{=h|aZV`5(3FJG2_t^9-GC!U@W9Y1Jf`+32-Y$|S= zJNEe}93azDcx1@<PNj9J7B?A~)dYTlJvgRgAN^7uY0G~!tmc&ZfIZ~;v3$kw4~u7H zGnsW>BIy;*s_0rYw$_XLiRNa{w0nNcONHZztzII-u{8BrvhQX{e2Q9l))JmyC>_zS zsMj2iMpNst>05$C948B7D$9z>r@4N!NhN4B$&TB?Lq$e(rj~lNGERn`g$vGmzSH8P zr)o-!y^`^wRUSQ4OzW8?9trc4Jej~tRhV>)-LsIh)p4887s-x&bW9pK<C}VYU8o%$ z6y+H0zfKw3uH8$;IK6yq>W>|^hGT~<`~Ms^XIdgUQ|$>qW^jpItWM|uRb8AvSiN~k z*m`{GY%9kl`d$kO9X9K-hP8P<vGr0K59gydEZxmE23#Tv_G0czb_8oo<(H4i=KScO zgj2ZLW_A)IlCtRFxdD;kTkep!N7Ca#rJ12^6mv7-aa$A}Hxu@!Ym~HOzE+z0bTUc* z|4pWj<5I8R@pM*3UgHoGCiBC`)Z~|peXH>C*eykc>&I^_I(`1JgOiE-*|s(>-?QeD R{OX#w^Qnnd`Nt++@E?d19vlDw delta 5401 zcmajid32Q39merHBw>d@fPe&LSSO%KNE8e)>;zD81C%JHFiGA_MkkXvGhq?vhzg1e zMPD`%sZ>y;bsbQOA}T^bMUAvbOSPp{&%x6pROmUit=jK1?~SdefAk)H^SSrV``-P1 zC+uD3TemRzNlxZkLpnk9BhIxoW{A(2ce|+8n0Yw_2C)~uiFtS&yW=?=jBR@ulYtlF zXe>gt7sjr*0(IY7?2IoU_a)71WU{IFGiKpgR6}25F@9s~i+a)t<&oBM>`i$RcEmZh zz783aX~4;N2L|x~w#NXo=zt?IoBmB18BO*I%*9Hq!$wp?$B=*K6dwWn4r$8-xOga* zqh?ft-LMJU;WF%mD^d5YMGastY9a?Qi~h|KG8)lQOyI|ui8Gj<8k&tN&&5Gli(09B zQ5~$pzPJ%D!Cg2Kzd)_5zmGTI5vZ-Gu;p2pJdcVn8O`7>WVOv|)QW7y&G;f}fY))c zuA76USdW^?7F)j^CsN*pTKd1ECNPH4Y33EEcCN;aSlO5L*ND$jp^o!8A$}}JbyS5K z$StUj79x`}NmN7YQ7f|rX~H~-^l9F}QFsF9U=Aly*F{nH#cg?MKh|Gg+)0Hxya(0M z8jRticmZ}j-<wGR>iUtkT!ynKPsGW%9w*@MaXDVV%@^TT)M0MHLd@vTdBKt-nG!PV z@M1iS!|)r_KmvYmuM1HFyacD>1T4pusF@!`t;|W}e44LOXCr%nH}E`EdxKDCU^wdg z<Y+Ql`U>ocHzMcHL{WRU9QAlTh}y#q)-9+3?LckO%c$!Q*zytU3DlCGvfrPz_5Vax zGHE&t^hVMZwX}V${ZXfUFsk9<))HG^X3OJI1Du8$;7n9IH={ZZT5q*BquNbkTRs2F zZN&rW3S%Bd&FB$S15a6BKy~m6YUXdDI%+`;;F$F!Y6bs-+L8>OSuJ%Q>irNvwO@+e z>EBEtqlPL`TTq1=7(+EYAJy?PRLA$Bu3vAz--MdcQ>Z<D#+G-Y?%RWEcfbAqIBFn& zz@)x7Lq;>r8tiqDjT&)3Th6!Tk*E$Ppst^W8sH4n7FD4-bTAX6wmyzJbc;~~y${vS z>cOmkCYkkA=*CT`k!?f$xV(g!cnEdl5md)VQ3L-N)$muSmGKSnuJ4L%DEC0!mx~%` zKUBv7RQrWPSpNe)W5!c4mWs9kZ_g@_N7z)M9;d}P93Mih%&RyI4<WajuTXp5C*S)` zC_=r6Za_WOO~^~sY{hoC7c=odlFSuk-o`BKMXMTN9;%~(sDTus8kmk9&_P~qrV%Uf zew>Fb*a1rzt!7+~TG6Sf--1eHtfn4oF}a$IM*cVSW9JKvDZm2M0OlYsEfYeW<`t-! zZAJ}rH>!huI0`>N&9L1?-uKz4iRGdO)(`K(q1aK+{|+*`VV757_M(>b5Ne6OMD6ie z)Ii!WI{ms0z%e)*HM6y-GqDYI{T|eS4<lnTCsBLerO=yjf9$5`e-xSRd@&Wf;u-9W z-{F<mxyXB7D^VTP;S^kKeG}VL?l8hL2Q||?`~?m{ZPACQS9KqL2zdFKi?NfQ|Le(g z!yxL$7;2_VP%H2#YK0z0oq_GBL-__y!;f$R`uQQzmQ-UlhEW4sgxZ2Tu{++2x^5#T zmyy{*MoTq_qpFTBLv=g}b>TGB({T+>#8r3|wxEmsFY&e{h1!x+Sc(DmDT?z@1AHIH zV|Nb9WjJFL>#vcmqC&1g9j=Wy4tJtvcn<XxjJeeNqjC<aybw7=W*us#TTt!nKyBso z*a`Pp-@z`FKSFKAXP2`6nz4qfhT5aHpocA=k6Oxn)E1SZR^)Qj8M)S4g}Uz+)Ibub zj+deav=VjwPf+)7LiP7V(pEf+YG9XjA8KHS?e{IHksr79pQ9T75_R7>R0rRp2GD7= zcYjY*hy74nI>?suQP(AlY(*)m!EvaLD^Q2*D%6cNsFkQk&1@m|!MjmQ`50<|yHSVi zpe-M_evWGA9QMYqF+<OP_cHH>UZ^DrU=J)o4QL9g!|AA*RH8bXi<&`$bw1`&PND|7 z4%N<+);+fVJ<Os06YQwx|F2}!!N2SU?KzrS(mtpW4@3<lfLfUX`~67!{Wx1c8Ffac z+j13ZfQ~h4U0}TfJLvgeNk$#HsE#(ER$?=1Mo*&}ejRnHTacwQe?;B)DeAscsQXT% zR_Y(97nYAd6n*F?s4~AH-Y4pb<P<(QGbThlM;s@9Mzp2{WcCmr5E?{`s3x8zMi5#l z4QdjhmsTaAbbyGabKYC<L-N{prA@>Q#OvDsAQ`3EM1lwq+TU%2lD0-^vPb%Gy-ofR zg4cq%lUPBlBa~VQy=?jutBBi)WyCH*Nk2ZVX^Hl~z?Np=BH}??z6!%OKOP?=?y=>U ztdHYQZT?c6XY)nYR(M1IPtu!G{ioA>J{Q~klXyAt0Fg^PLFgp6rhR1M#8hH{t(<8+ z58oqRBly3INfGH64?ayOT}b2+Iy1?`d?;N(93|c$UM6aY2IA+0(%l~E&xiPY!ItZ+ zJUr%A;$Gqyv6^TkULoEkl&&QP5p4*)J4ng&BXSElelyGtVg_+Pq4beQ`mxi?=t^5| z!h^(q;@7s0_enaf=ksP_8ZnS?38gv2?}+DBAPpv#YW=TE7rp<dogn`rv7IQi^;cWh z;>ARTEmv8!g})+(5#xxS#4iawnyqQG%^bps#6n_->U8rn%8)h^ImAd}C81P8+)6w} zloM-+Hwpb5zeVgOt|6``HV{h9#Ljfim^-kRSWaXU`qfnGOZ<pPzQf0GB7;!cO0-Sq zc*WvS;)pHZi21}#wtO3QwE2f|y3M!pTQYkI$5uRw_Yqr&AA5CeOvL>x=UD3V9$VYE zPv;JIPvm~+?(F?1cYmML?(65BZSSvj>VnOYMCxSU#*Cpen`>&Ec)YGT5?RDI5hvl) z`iI2*;e^u=FEq1)p-?y)N^Q8H+2_XmtK7K*YUeEoM<V`e$KMolnw)4YHzXSUiF&8C zWsKLv!cB>AW0WT9!*T!rz2#PC(SpWUtv?cuC)_0i*Q6#4TI|aRCW5IwgX?^5@z9Bx zkzhFL-Zu1T$Lfe<5<x!W?u5YD^TUaV<Bv5iFp1WjKNzj`*EB|&8=~&gz_R@MM53vz zs3;Up)Hhcb)-*O0)j8p4O+);9!|`}C&3zl_?T*QBpH*C3R$Sr^%-`jHntxO0>A`5I zIT&)vn3y|e*y&XD@PZ8Yxq?#nOu^~YslqH@Dlnp#FLh1v0AFf-$-5c-S-^^LG!fgs zHRSk1PGtW}@tXR?f0lFisD#gbzckO?S-QsEHo7tCpU9Hc$DD9=b2P+iu@dteWAqpE z&rC3zV63*_2bVDZkW;t+)ex;t4m)v&7DBObU7h1!;KXX3sCR$Z`S1JF7sR#1j{gS@ zxF^fLNcAkA?#r4SOgPch+%b3g+;d}ZZpWY^;hK8)>T##K%?egK5tiN>bw`aa9x#i8 a61m+8tN#0}znS$fh&Kfz3CFD)Kl|V88LmPA diff --git a/feincms/locale/de/LC_MESSAGES/django.po b/feincms/locale/de/LC_MESSAGES/django.po index 2f3530775..f846c2fc5 100644 --- a/feincms/locale/de/LC_MESSAGES/django.po +++ b/feincms/locale/de/LC_MESSAGES/django.po @@ -1,745 +1,780 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Matthias Kestenholz <mk@feinheit.ch>, 2011 # sbaechler <simon@stellanera.com>, 2013 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: German (http://www.transifex.com/projects/p/feincms/language/de/)\n" +"Language-Team: German (http://www.transifex.com/projects/p/feincms/language/" +"de/)\n" +"Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "Template" - -#: models.py:510 -msgid "ordering" -msgstr "Sortierung" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "Sprache" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Alle" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Übergeordnet" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategorie" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "%s ändern" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "Titel" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" +"Sie haben die nötige Berechtigung nicht, um dieses Objekt zu bearbeiten" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "Keine Berechtigung" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s wurde an eine neue Position verschoben." -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Unbekannter Verschiebe-Befehl." -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "Aktionen" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." +#: admin/tree_editor.py:552 +#, fuzzy, python-format +#| msgid "Successfully deleted %(count)d items." +msgid "Successfully deleted %(count)d items." msgstr "%s Einträge gelöscht." -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "Ausgewählte %(verbose_name_plural)s löschen" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "Applikation" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "Applikationen" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "Applikation" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "aktiviert" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Neue Kommentare können hinzugefügt werden" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "Kommentare" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "veröffentlicht" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "nicht öffentlich" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "Name" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "E-Mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "Betreff" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "Inhalt" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "Kontaktformular" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "Kontaktformulare" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "Datei" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "Dateien" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "Bild" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "Alternativtext" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "Bildlegende" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "Legende" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "Bilder" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "Position" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "Format" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "Mediendatei" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "Mediendateien" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "Typ" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "Roh-Inhalt" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "Roh-Inhalte" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "HTML-Validierungswarnungen ignorieren" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "Die HTML-Validierung ergab %(count)d Warnungen. Bitte überprüfen Sie den aktualisierten Inhalt bevor Sie fortfahren: %(messages)s" +msgstr "" +"Die HTML-Validierung ergab %(count)d Warnungen. Bitte überprüfen Sie den " +"aktualisierten Inhalt bevor Sie fortfahren: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "Text" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "Text" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "Texte" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "Der RSS Feed wird mehrmals täglich aktualisiert. Eine Änderung des Titels erscheint erst nach der nächsten Feed-Aktualisierung auf der Webseite." +msgstr "" +"Der RSS Feed wird mehrmals täglich aktualisiert. Eine Änderung des Titels " +"erscheint erst nach der nächsten Feed-Aktualisierung auf der Webseite." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "Link" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "Vor-gerenderter Inhalt" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "Letzte Aktualisierung" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "Maximale Anzahl" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS Feed" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "RSS Feeds" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "Sektion" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "Sektionen" -#: content/table/models.py:63 -msgid "plain" -msgstr "schlicht" - -#: content/table/models.py:64 -msgid "title row" -msgstr "Titelzeile" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "Titelzeile und -spalte" - -#: content/table/models.py:72 -msgid "table" -msgstr "Tabelle" - -#: content/table/models.py:73 -msgid "tables" -msgstr "Tabellen" - -#: content/table/models.py:87 -msgid "data" -msgstr "Daten" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "Template" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "Templates" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "Template" + +#: content/video/models.py:34 msgid "video link" msgstr "Video-Link" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Dies sollte ein Link zu einem Youtube- oder vimeo-Video sein, z.B.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Dies sollte ein Link zu einem Youtube- oder vimeo-Video sein, z.B.: http://" +"www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "Video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "Videos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "Tagging" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "Sortierung" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "Begriffe" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "Sprache" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "Übersetzung von" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Dieses Feld für Einträge in der Primärsprache leer lassen." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "Verfügbare Übersetzungen" + +#: module/blog/models.py:33 msgid "published" msgstr "veröffentlicht" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Dies wird auch für die generierte Navigation verwendet." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "veröffentlicht am" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Wird automatisch gesetzt, wenn `veröffentlicht` aktiviert ist." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "Eintrag" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "Einträge" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "Begriffe" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "Übersetzung von" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Dieses Feld für Einträge in der Primärsprache leer lassen." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "Verfügbare Übersetzungen" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "Erstellt um" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "Verändert um" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "Inhaltstypen" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "Veröffentlichen am" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "Veröffentlicht bis" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Leer lassen wenn das Element ewig aktiv bleiben soll." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "sichtbar von – bis" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Datumsbasierte Veröffentlichung" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "Feature" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Feature" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "Meta Begriffe" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Diese Begriffe werden vor die Standard-Begriffsliste eingefügt." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "Begriffe werden von den meisten Suchmaschinen ignoriert." -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "Meta Beschreibung" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Diese Beschreibung wird vor der Standard-Beschreibung eingefügt." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" +"Dieser Text wird auf der Suchresultatsseite angezeigt. Für das SEO Ranking " +"wird er nicht verwendet. Sollte nicht länger als 140 Zeichen sein." -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Suchmaschinenoptimierung" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Übersetzungen bearbeiten" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Übersetzung erstellen" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "Übersetzungen" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "Dies würde eine Endlosschleife in der Hierarchie erzeugen." -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "Dateien verschiedenen Typs können nicht überschrieben werden. (%(old_ext)s durch %(new_ext)s)." +msgstr "" +"Dateien verschiedenen Typs können nicht überschrieben werden. (%(old_ext)s " +"durch %(new_ext)s)." -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "Erfolgreich %(count)d Mediendatei zu %(category)s hinzugefügt." msgstr[1] "Erfolgreich %(count)d Mediendateien zu %(category)s hinzugefügt." -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "Ausgewählte Mediendateien zu Kategorie hinzufügen" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "ZIP-Datei als %s exportiert." -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "ZIP Export fehlgeschlagen: %s" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "Ausgewählte Mediendateien als ZIP-Archiv exportieren." -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Vorschau" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "Dateigrösse" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "Erstellt" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "Dateityp" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "Dateiinfo" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "%d Dateien importiert" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "ZIP Import fehlgeschlagen: %s" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr " Keine Datei angegeben" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "Übergeordnet" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "Slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "Kategorie" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "Kategorien" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "Copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Bild" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF-Dokument" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Text" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Text" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "ZIP-Archiv" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binärdaten" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "Beschreibung" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "Mediendatei-Übersetzung" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "Mediendatei-Übersetzungen" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "Auszug" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Kurze Zusammenfassung des Seiteninhaltes." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Auszug" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "Navigations-Erweiterung" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "Wähle das Modul aus, welches weitere Navigationspunkte erstellt." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Navigations-Erweiterung" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "Standard" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "Fusszeile" + +#: module/page/extensions/navigationgroups.py:28 +msgid "navigation group" +msgstr "Navigationsgruppe" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Seiten auswählen, welche als ähnlicher Inhalt angezeigt werden sollen." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Verwandte Seiten" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "Seite" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "Verbundene Seite" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "" +"Der angezeigte Inhalt wird durch den Inhalt der angegebenen Seite ersetzt." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "Inhaltstitel" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "Die erste Zeile ist der Haupttitel, die weiteren Zeilen Untertitel" + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "Seitentitel" + +#: module/page/extensions/titles.py:30 +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Seitentitel für das Browser-Fenster. Standardmässig gleich wie der Titel." +"Darf nicht länger als 70 Zeichen sein." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Titel" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Die URL wird schon von einer aktiven Seite verwendet." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Die URL wird schon von einer anderen aktiven Seite verwendet." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "Diese Seite erlaubt keine Unterseiten" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Weitere Optionen" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "Im Menü" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Unterseite hinzufügen" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Auf der Webseite anzeigen" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" -msgstr "" +msgid "Add %(language)s translation of \"%(page)s\"" +msgstr "%(language)s-Übersetzung für \"%(page)s\" hinzufügen" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "Der Inhalt der Originalseite wurde auf die neue Seite kopiert." -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" -msgstr "Sie haben die nötige Berechtigung nicht, um dieses Objekt zu bearbeiten" +msgstr "" +"Sie haben die nötige Berechtigung nicht, um dieses Objekt zu bearbeiten" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "geerbt" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "Erweiterungen" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "Aktiv" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "Aktiv" -#: module/page/models.py:175 +#: module/page/models.py:173 +msgid "This title is also used for navigation menu items." +msgstr "Dieser Titel wird auch für die generierte Navigation verwendet." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "Dies wird verwendet um die URL der Seite zu generieren" + +#: module/page/models.py:184 msgid "override URL" msgstr "Überschriebene URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Überschreibe die URL. Am Anfang und Ende muss ein / stehen, falls es sich um eine lokale URL handelt. Dieses Feld bestimmt die Navigation und die URLs von Unterseiten." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Überschreibe die URL. Am Anfang und Ende muss ein / stehen, falls es sich um " +"eine lokale URL handelt. Dieses Feld bestimmt die Navigation und die URLs " +"von Unterseiten." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "Weiterleiten zu" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" +"Adresse für automatische Weiterleitungen, oder Primärschlüssel einer Seite" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "Zwischengespeicherte URL" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" +"Diese %(page_class)s verwendet ein Singleton Template, und " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" + +#: module/page/models.py:426 msgid "page" msgstr "Seite" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "Seiten" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "Auszug" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Kurze Zusammenfassung des Seiteninhaltes." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Auszug" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "Navigations-Erweiterung" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Wähle das Modul aus, welches weitere Navigationspunkte erstellt." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Navigations-Erweiterung" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Seiten auswählen, welche als ähnlicher Inhalt angezeigt werden sollen." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Verwandte Seiten" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "Seite" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "Verbundene Seite" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Der angezeigte Inhalt wird durch den Inhalt der angegebenen Seite ersetzt." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "Inhaltstitel" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "Die erste Zeile ist der Haupttitel, die weiteren Zeilen Untertitel" - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "Seitentitel" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Seitentitel für das Browser-Fenster. Standardmässig gleich wie der Titel." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Titel" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr " Nach %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Element wirklich löschen?" @@ -771,10 +806,13 @@ msgstr "Template wirklich ändern? <br />Alle Änderungen werden gespeichert." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." -msgstr "Template wechseln? <br />Alle Änderungen werden sofort gespeichert und Inhalt von \n<strong>%%(source_region)s</strong> nach <strong>%%(target_region)s</strong> verschoben." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +msgstr "" +"Template wechseln? <br />Alle Änderungen werden sofort gespeichert und " +"Inhalt von \n" +"<strong>%%(source_region)s</strong> nach <strong>%%(target_region)s</strong> " +"verschoben." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -798,7 +836,7 @@ msgstr "Neu einfügen:" #: templates/admin/feincms/content_editor.html:15 msgid "Copy content from the original" -msgstr "" +msgstr "Inhalt von Original übernehmen" #: templates/admin/feincms/content_editor.html:19 msgid "Region empty" @@ -808,22 +846,24 @@ msgstr "Region leer" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Inhalt wird von der übergeordneten Seite geerbt. Füge Inhalt hinzu, um dieses Verhalten zu ändern" +msgstr "" +"Inhalt wird von der übergeordneten Seite geerbt. Füge Inhalt hinzu, um " +"dieses Verhalten zu ändern" #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Neues Element hinzufügen" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "Weiteres %(verbose_name)s hinzufügen" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "Entfernen" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Sichern" @@ -851,13 +891,21 @@ msgstr "runter" msgid "remove" msgstr "entfernen" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "In der Seite bearbeiten" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Startseite" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Hinzufügen" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -880,29 +928,26 @@ msgstr "%(verbose_name)s zurücksetzen" msgid "Press the save button below to revert to this version of the object." msgstr "Speichern drücken, um zu dieser Version des Objektes zurückzukehren." -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Schnellzugriffe" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Alles zuklappen" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Alles aufklappen" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "In der Seite bearbeiten" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Hinzufügen" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " Nach %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -915,7 +960,8 @@ msgstr "Kategorie auswählen:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "Die folgenden Mediendateien werdene zur ausgewählten Kategorie hinzugefügt:" +msgstr "" +"Die folgenden Mediendateien werdene zur ausgewählten Kategorie hinzugefügt:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -946,9 +992,12 @@ msgstr "%(comment_count)s Kommentare." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" " " -msgstr "\n%(comment_username)s schrieb am %(comment_submit_date)s<br />" +msgstr "" +"\n" +"%(comment_username)s schrieb am %(comment_submit_date)s<br />" #: templates/content/comments/default.html:28 msgid "No comments." @@ -965,3 +1014,27 @@ msgstr "Senden" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Danke!" + +#~ msgid "plain" +#~ msgstr "schlicht" + +#~ msgid "title row" +#~ msgstr "Titelzeile" + +#~ msgid "title row and column" +#~ msgstr "Titelzeile und -spalte" + +#~ msgid "table" +#~ msgstr "Tabelle" + +#~ msgid "tables" +#~ msgstr "Tabellen" + +#~ msgid "data" +#~ msgstr "Daten" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Diese Begriffe werden vor die Standard-Begriffsliste eingefügt." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Diese Beschreibung wird vor der Standard-Beschreibung eingefügt." diff --git a/feincms/locale/en/LC_MESSAGES/django.po b/feincms/locale/en/LC_MESSAGES/django.po index c7f2fdc33..da4414571 100644 --- a/feincms/locale/en/LC_MESSAGES/django.po +++ b/feincms/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,724 +17,737 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "" - -#: models.py:510 -msgid "ordering" -msgstr "" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." msgstr "" -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "" -#: content/table/models.py:63 -msgid "plain" +#: content/template/models.py:53 +msgid "template content" +msgstr "" + +#: content/template/models.py:54 +msgid "template contents" msgstr "" -#: content/table/models.py:64 -msgid "title row" +#: content/template/models.py:63 models.py:400 +msgid "template" msgstr "" -#: content/table/models.py:66 -msgid "title row and column" +#: content/video/models.py:34 +msgid "video link" msgstr "" -#: content/table/models.py:72 -msgid "table" +#: content/video/models.py:36 +msgid "" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" msgstr "" -#: content/table/models.py:73 -msgid "tables" +#: content/video/models.py:41 +msgid "video" msgstr "" -#: content/table/models.py:87 -msgid "data" +#: content/video/models.py:42 +msgid "videos" msgstr "" -#: content/template/models.py:51 -msgid "template content" +#: contrib/tagging.py:132 +msgid "Tagging" msgstr "" -#: content/template/models.py:52 -msgid "template contents" +#: models.py:550 +msgid "ordering" msgstr "" -#: content/video/models.py:31 -msgid "video link" +#: module/blog/extensions/tags.py:17 +msgid "tags" msgstr "" -#: content/video/models.py:32 -msgid "" -"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." -"com/watch?v=zmj1rpzDRZ0" +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" msgstr "" -#: content/video/models.py:37 -msgid "video" +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" msgstr "" -#: content/video/models.py:38 -msgid "videos" +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." msgstr "" -#: contrib/tagging.py:117 -msgid "Tagging" +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" msgstr "" -#: module/blog/models.py:28 +#: module/blog/models.py:33 msgid "published" msgstr "" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "" -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "" -#: module/blog/models.py:34 +#: module/blog/models.py:42 msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "" -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "" -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "" -#: module/page/forms.py:172 -msgid "This URL is already taken by an active page." +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" msgstr "" -#: module/page/forms.py:190 -msgid "This URL is already taken by another active page." +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." msgstr "" -#: module/page/modeladmins.py:41 -msgid "Other options" +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" msgstr "" -#: module/page/modeladmins.py:90 module/page/models.py:174 -msgid "in navigation" +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" msgstr "" -#: module/page/modeladmins.py:105 -msgid "Add child page" +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." msgstr "" -#: module/page/modeladmins.py:107 -#: templates/admin/feincms/content_inline.html:9 -msgid "View on site" +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" msgstr "" -#: module/page/modeladmins.py:126 -#, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" msgstr "" -#: module/page/modeladmins.py:156 -msgid "" -"The content from the original translation has been copied to the newly " -"created page." +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" msgstr "" -#: module/page/modeladmins.py:170 -msgid "You don't have the necessary permissions to edit this object" +#: module/page/extensions/navigationgroups.py:28 +msgid "navigation group" msgstr "" -#: module/page/modeladmins.py:185 -msgid "inherited" +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." msgstr "" -#: module/page/modeladmins.py:189 -msgid "extensions" +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" msgstr "" -#: module/page/modeladmins.py:193 module/page/models.py:206 -msgid "is active" +#: module/page/extensions/sites.py:21 +msgid "Site" msgstr "" -#: module/page/models.py:167 -msgid "active" +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" msgstr "" -#: module/page/models.py:175 -msgid "override URL" +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." msgstr "" -#: module/page/models.py:176 +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "" + +#: module/page/extensions/titles.py:30 msgid "" -"Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages' " -"URLs." +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." msgstr "" -#: module/page/models.py:177 -msgid "redirect to" +#: module/page/extensions/titles.py:60 +msgid "Titles" msgstr "" -#: module/page/models.py:178 -msgid "Target URL for automatic redirects or the primary key of a page." +#: module/page/forms.py:187 +msgid "This URL is already taken by an active page." msgstr "" -#: module/page/models.py:180 -msgid "Cached URL" +#: module/page/forms.py:206 +msgid "This URL is already taken by another active page." msgstr "" -#: module/page/models.py:395 -msgid "page" +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" msgstr "" -#: module/page/models.py:396 -msgid "pages" +#: module/page/modeladmins.py:42 +msgid "Other options" msgstr "" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" +#: module/page/modeladmins.py:80 module/page/models.py:182 +msgid "in navigation" msgstr "" -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 +msgid "Add child page" msgstr "" -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 +#: templates/admin/feincms/content_inline.html:9 +msgid "View on site" msgstr "" -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" +#: module/page/modeladmins.py:142 +#, python-format +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/extensions/navigation.py:110 +#: module/page/modeladmins.py:177 msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." +"The content from the original translation has been copied to the newly " +"created page." msgstr "" -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" +#: module/page/modeladmins.py:197 +msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." +#: module/page/modeladmins.py:223 +msgid "inherited" msgstr "" -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" +#: module/page/modeladmins.py:229 +msgid "extensions" msgstr "" -#: module/page/extensions/sites.py:16 -msgid "Site" +#: module/page/modeladmins.py:233 module/page/models.py:221 +msgid "is active" msgstr "" -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" +#: module/page/models.py:169 +msgid "active" msgstr "" -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." +#: module/page/models.py:173 +msgid "This title is also used for navigation menu items." msgstr "" -#: module/page/extensions/titles.py:13 -msgid "content title" +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" msgstr "" -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." +#: module/page/models.py:184 +msgid "override URL" msgstr "" -#: module/page/extensions/titles.py:15 -msgid "page title" +#: module/page/models.py:186 +msgid "" +"Override the target URL. Be sure to include slashes at the beginning and at " +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" + +#: module/page/models.py:190 +msgid "redirect to" msgstr "" -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." +#: module/page/models.py:193 +msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/extensions/titles.py:43 -msgid "Titles" +#: module/page/models.py:196 +msgid "Cached URL" msgstr "" -#: templates/admin/filter.html:3 +#: module/page/models.py:298 #, python-format -msgid " By %(filter_title)s " +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 +msgid "page" +msgstr "" + +#: module/page/models.py:427 +msgid "pages" msgstr "" #: templates/admin/feincms/_messages_js.html:4 @@ -810,16 +823,16 @@ msgstr "" msgid "Add new item" msgstr "" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "" @@ -847,13 +860,21 @@ msgstr "" msgid "remove" msgstr "" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -876,28 +897,25 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " msgstr "" #: templates/admin/medialibrary/add_to_category.html:5 diff --git a/feincms/locale/es/LC_MESSAGES/django.po b/feincms/locale/es/LC_MESSAGES/django.po index 5d2fbad59..d0781b932 100644 --- a/feincms/locale/es/LC_MESSAGES/django.po +++ b/feincms/locale/es/LC_MESSAGES/django.po @@ -1,744 +1,776 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # proycon <proycon@anaproy.nl>, 2009 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Spanish (http://www.transifex.com/projects/p/feincms/language/es/)\n" +"Language-Team: Spanish (http://www.transifex.com/projects/p/feincms/language/" +"es/)\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "plantilla" - -#: models.py:510 -msgid "ordering" -msgstr "orden" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "idioma" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Todos" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Padre" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoría" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "título" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s ha sido movido a una nueva posición" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "No entiendo la orden de movimiento" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "acciones" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "contenido de la aplicación" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "contenidos de la aplicación" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplicación" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "activo" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Se podrán añadir nuevos comentarios" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "comentarios" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "público" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "privado" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nombre" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "e-mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "asunto" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "contenido" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "formulario de contacto" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "formularios de contacto" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "archivo" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "archivos" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "imagen" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "leyenda" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "imágenes" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "posición" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "archivo de medios" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "archivos de medios" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tipo" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "contenido crudo" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "contenidos crudos" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Ignorar los avisos de validación HTML" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "La validación del HTML produjo %(count)d avisos. Por favor revisa el contenido actualizado de la parte inferior antes de continuar: %(messages)s" +msgstr "" +"La validación del HTML produjo %(count)d avisos. Por favor revisa el " +"contenido actualizado de la parte inferior antes de continuar: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "texto" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "textos ricos" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "El feed RSS es actualizado varias veces por dia. Cambios en el título solo aparecen en la página después de la actualización del feed RSS siguiente." +msgstr "" +"El feed RSS es actualizado varias veces por dia. Cambios en el título solo " +"aparecen en la página después de la actualización del feed RSS siguiente." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "enlace" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "contenido pre-renderizado" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "última actualización" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "número máximo" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "feed RSS" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "feeds RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "sección" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "secciones" -#: content/table/models.py:63 -msgid "plain" -msgstr "plano" - -#: content/table/models.py:64 -msgid "title row" -msgstr "título de la fila" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "título de fila y columna" - -#: content/table/models.py:72 -msgid "table" -msgstr "tabla" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tablas" - -#: content/table/models.py:87 -msgid "data" -msgstr "datos" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "plantilla de contenido" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "plantilla de contenidos" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "plantilla" + +#: content/video/models.py:34 msgid "video link" msgstr "enlace de vídeo" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Debe ser un enlace a un vídeo de YouTube o Vimeo. Por ejemplo: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Debe ser un enlace a un vídeo de YouTube o Vimeo. Por ejemplo: http://www." +"youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "vídeo" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "vídeos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "orden" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "etiquetas" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "idioma" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "traducción de" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Deja este campo vacío para las entradas en el idioma base." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "traducciones disponibles" + +#: module/blog/models.py:33 msgid "published" msgstr "publicado" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "También será usado para la navegación generada automáticamente." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publicado en" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Se establecerá automáticamente cuando se marque en 'publicado'." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "entrada" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "entradas" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "etiquetas" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "traducción de" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Deja este campo vacío para las entradas en el idioma base." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "traducciones disponibles" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "fecha de creación" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "fecha de modificación" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "tipos de contenido" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "fecha de publicación" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "publicar hasta" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Si se deja en blanco la entrada permanecerá activa para siempre." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "visible de - hasta" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Publicación según la fecha" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "categorizado" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Categorizado" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta palabras clave" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Será incluido antes de la lista de palabras clave." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta descripción" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Será incluido antes de la meta descripción por defecto." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Optimización para motores de búsqueda" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Editar traducción" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Crear traducción" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "traducciones" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Pre-visualización" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "tamaño de archivo" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "creado en" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "tipo de archivo" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "información del archivo" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "padre" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "categoría" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "categorías" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Imagen" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "documento PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Texto" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Texto rico" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binario" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "descripción" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "traducción del archivo de media" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "traducciones del archivo de media" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "extracto" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Añade una breve descripción resumiendo el contenido de la página." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Extracto" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "extensión de navegación" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Selecciona el módulo que provee sub-páginas para esta pagina si necesitas " +"personalizar la navegación." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Extensión de navegación" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "en la navegación" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Selecciona las páginas que se mostrarán como contenido relacionado." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Páginas relacionadas" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "página direccionada" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Todo el contenido es heredado de esta página." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "título del contenido" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" +"La primera línea es el título principal. Otras líneas serán subtítulos." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "título de la página" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Título de la página para la ventana del navegador. Si se omite utilizará el " +"mismo título." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Títulos" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Esta URL ya está en uso en una página activa" -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Esta URL ya está en uno por otra página activa" -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "otras opciones" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "en la navegación" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Añade una página hija" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Ver en sitio" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "heredado" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "extensiones" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "activo" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "activo" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "También será usado para la navegación generada automáticamente." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "URL efectivo" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "URL efectivo. Debe contener una '/' cuando se trata de un URL local. Este campo afecta la navegación y los URLs de las sub-páginas." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"URL efectivo. Debe contener una '/' cuando se trata de un URL local. Este " +"campo afecta la navegación y los URLs de las sub-páginas." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "redirección a" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "URL en cache" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "página" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "páginas" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "extracto" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Añade una breve descripción resumiendo el contenido de la página." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Extracto" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "extensión de navegación" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Selecciona el módulo que provee sub-páginas para esta pagina si necesitas personalizar la navegación." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Extensión de navegación" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Selecciona las páginas que se mostrarán como contenido relacionado." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Páginas relacionadas" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "página direccionada" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Todo el contenido es heredado de esta página." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "título del contenido" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "La primera línea es el título principal. Otras líneas serán subtítulos." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "título de la página" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Título de la página para la ventana del navegador. Si se omite utilizará el mismo título." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Títulos" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "Por %(filter_title)s" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "¿Confirma la eliminación del elemento?" @@ -757,7 +789,8 @@ msgstr "Imposible de eliminar el elemento" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Imposible de eliminar el elemento, porque es padre de al menos un elemento ." +msgstr "" +"Imposible de eliminar el elemento, porque es padre de al menos un elemento ." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -770,9 +803,8 @@ msgstr "¿Deas cambiar la plantilla?<br /> Todos los cambios se guardarán." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -807,22 +839,24 @@ msgstr "Región vacía" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "El contenido del sitio padre se hereda automáticamente. Para sobreescribir este comportamiento añade algún contenido." +msgstr "" +"El contenido del sitio padre se hereda automáticamente. Para sobreescribir " +"este comportamiento añade algún contenido." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Añadir nuevo elemento" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Guardar" @@ -850,13 +884,21 @@ msgstr "abajo" msgid "remove" msgstr "borrar" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Editar en el sitio" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Página inicial" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -879,29 +921,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Atajos" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Colapsar el árbol" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Expandir el árbol" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Editar en el sitio" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Por %(filter_title)s" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -945,9 +984,13 @@ msgstr "%(comment_count)s comentarios." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s dijo el %(comment_submit_date)s<br />\n" " " -msgstr "\n %(comment_username)s dijo el %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -964,3 +1007,27 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "¡Gracias!" + +#~ msgid "plain" +#~ msgstr "plano" + +#~ msgid "title row" +#~ msgstr "título de la fila" + +#~ msgid "title row and column" +#~ msgstr "título de fila y columna" + +#~ msgid "table" +#~ msgstr "tabla" + +#~ msgid "tables" +#~ msgstr "tablas" + +#~ msgid "data" +#~ msgstr "datos" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Será incluido antes de la lista de palabras clave." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Será incluido antes de la meta descripción por defecto." diff --git a/feincms/locale/fr/LC_MESSAGES/django.po b/feincms/locale/fr/LC_MESSAGES/django.po index 6b714665f..c52cd5149 100644 --- a/feincms/locale/fr/LC_MESSAGES/django.po +++ b/feincms/locale/fr/LC_MESSAGES/django.po @@ -1,743 +1,776 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: French (http://www.transifex.com/projects/p/feincms/language/fr/)\n" +"Language-Team: French (http://www.transifex.com/projects/p/feincms/language/" +"fr/)\n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "modèle" - -#: models.py:510 -msgid "ordering" -msgstr "séquence" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "langue" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Tous" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Parent" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Changement %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "titre" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "actions" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "contenu d'application" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "contenus d'application" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "application" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nom" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "courriel" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "sujet" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "Contenu" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "formulaire de contact" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "formulaires de contact" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "fichier" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "fichiers" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "image" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "légende" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "images" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "position" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "fichier de média" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "fichiers de média" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "type" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "contenu cru" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "contenus crus" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "texte" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "texte" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "textes" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "Le champ rss est mis à jour plusieurs fois par jour. Un changement dans le titre ne sera visible que sur la page d'accueil après la mise à jour prochaine." +msgstr "" +"Le champ rss est mis à jour plusieurs fois par jour. Un changement dans le " +"titre ne sera visible que sur la page d'accueil après la mise à jour " +"prochaine." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "lien" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "contenu généré" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "mise à jour" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "max. éléments" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "Fil RSS" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "Fils RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "section" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "sections" -#: content/table/models.py:63 -msgid "plain" -msgstr "plaine" - -#: content/table/models.py:64 -msgid "title row" -msgstr "titre de la ligne" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "ligne de titre et de la colonne" - -#: content/table/models.py:72 -msgid "table" -msgstr "tableau" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tableaux" - -#: content/table/models.py:87 -msgid "data" -msgstr "données" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "modèle" + +#: content/video/models.py:34 msgid "video link" msgstr "lien du vidéo" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Cela devrait être un lien vers une vidéo YouTube ou Vimeo, à savoir: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Cela devrait être un lien vers une vidéo YouTube ou Vimeo, à savoir: http://" +"www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "vidéo" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "vidéos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "séquence" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "mots-clé" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "langue" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "traduction de" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "" + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "traductions disponibles" + +#: module/blog/models.py:33 msgid "published" msgstr "publié" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Il est utilisé pour la navigation généré aussi." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publié le" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Sera mis automatiquement une fois que vous cochez la case «publié» ci-dessus." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Sera mis automatiquement une fois que vous cochez la case «publié» ci-dessus." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "entrée" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "entrées" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "mots-clé" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "traduction de" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "traductions disponibles" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "date de création" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "date de modification" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "types de contenu" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "date de la publication" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "date de termination de la publication" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Laissez vide si l'entrée doit rester active pour toujours." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "visible de - à" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "termes meta" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Ce sera ajouté à la liste de mots clés par défaut." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "description meta" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Ce sera ajouté à la description par défaut." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Modifier la traduction" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Créer traduction" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "traductions" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Prévisualiser" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "taille" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "crée" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "type de fichier" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "parent" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "télougou" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "catégorie" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "catégories" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "image" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "Document PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "texte" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Données binaires" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "description" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "traductions du fichier de média" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "traductions des fichiers de média" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "additif de la navigation" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Sélectionnez le module fournissant pages pour cette page si vous avez besoin " +"de personnaliser la navigation." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "à la navigation" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "" + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Tout le contenu est hérité de cette page si donnée." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "titre du contenu" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" +"La première ligne est le titre principal, les lignes suivantes sont des sous-" +"titres." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "titre de la page" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Titre de la page pour fenêtre de navigateur. Même que le titre par défaut." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Cette URL est déjà prise par une page active." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Cette URL est déjà pris par une autre page active." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Autres options" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "à la navigation" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Ajouter page enfant" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Voir sur le site" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "hérité" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "extensions" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "actif" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Il est utilisé pour la navigation généré aussi." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "adresse URL forcée" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Outrepasser l'URL cible. N'oubliez pas d'inclure des barres obliques au début et à la fin s'il s'agit d'une URL locale. Cela affecte la navigation et les adresses URL des sous-pages." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Outrepasser l'URL cible. N'oubliez pas d'inclure des barres obliques au " +"début et à la fin s'il s'agit d'une URL locale. Cela affecte la navigation " +"et les adresses URL des sous-pages." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "rediriger à" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "adresse URL temporairement enregistrée" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "page" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "pages" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "additif de la navigation" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Sélectionnez le module fournissant pages pour cette page si vous avez besoin de personnaliser la navigation." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "" - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Tout le contenu est hérité de cette page si donnée." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "titre du contenu" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "La première ligne est le titre principal, les lignes suivantes sont des sous-titres." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "titre de la page" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Titre de la page pour fenêtre de navigateur. Même que le titre par défaut." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "Par %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Vraiment supprimer cet élément?" @@ -756,7 +789,9 @@ msgstr "Impossible de supprimer cet élément" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Impossible de supprimer l'élément, parce qu'il est le parent d'au moins un autre élément." +msgstr "" +"Impossible de supprimer l'élément, parce qu'il est le parent d'au moins un " +"autre élément." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -764,14 +799,15 @@ msgstr "Changer modèle" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." -msgstr "Réellement changer de modèle? <br /> Toutes les modifications sont enregistrées." +msgstr "" +"Réellement changer de modèle? <br /> Toutes les modifications sont " +"enregistrées." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -806,22 +842,24 @@ msgstr "Région vide" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Contenu du site parent est automatiquement hérité. Pour contourner ce comportement, ajoutez un peu de contenu." +msgstr "" +"Contenu du site parent est automatiquement hérité. Pour contourner ce " +"comportement, ajoutez un peu de contenu." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Ajouter un autre" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Enregistrer" @@ -849,13 +887,21 @@ msgstr "vers le bas" msgid "remove" msgstr "supprimer" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Page d'accueil" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -878,29 +924,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Raccourcis" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Réduire l'arbre" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Développer l'arborescence" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtre" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Par %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -944,7 +987,8 @@ msgstr "" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" " " msgstr "" @@ -963,3 +1007,27 @@ msgstr "Envoyer" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Merci!" + +#~ msgid "plain" +#~ msgstr "plaine" + +#~ msgid "title row" +#~ msgstr "titre de la ligne" + +#~ msgid "title row and column" +#~ msgstr "ligne de titre et de la colonne" + +#~ msgid "table" +#~ msgstr "tableau" + +#~ msgid "tables" +#~ msgstr "tableaux" + +#~ msgid "data" +#~ msgstr "données" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Ce sera ajouté à la liste de mots clés par défaut." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Ce sera ajouté à la description par défaut." diff --git a/feincms/locale/hr/LC_MESSAGES/django.po b/feincms/locale/hr/LC_MESSAGES/django.po index 0a562024c..2ef4eef95 100644 --- a/feincms/locale/hr/LC_MESSAGES/django.po +++ b/feincms/locale/hr/LC_MESSAGES/django.po @@ -1,446 +1,439 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Bojan Mihelač <bmihelac@mihelac.org>, 2010 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Croatian (http://www.transifex.com/projects/p/feincms/language/hr/)\n" +"Language-Team: Croatian (http://www.transifex.com/projects/p/feincms/" +"language/hr/)\n" +"Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: hr\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" - -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "predložak" - -#: models.py:510 -msgid "ordering" -msgstr "poredak" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "jezik" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Svi" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Nadređeni" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategorija" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Promjeni %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "naziv" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s je premještena na novu poziciju." -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Uputa za premještanje nije uspješno interpretirana. " -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "akcije" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "sadržaj aplikacije" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "sadržaji aplikacije" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplikacija" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "omogućeno" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Novi komentari mogu biti dodani" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "komentari" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "objavljeno" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "neobjavljeno" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "ime" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "email" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "naslov" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "sadržaj" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "kontaktni obrazac" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "kontaktni obrazci" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "datoteka" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "datoteke" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "slika" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "naslov" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "slike" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "pozicija" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "medijska datoteka" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "medijske datoteke" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tip" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "neformatirani sadržaj" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "neformatirani sadržaji" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Zanemariti upozorenja HTML provjere" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "HTML provjera je pokazala %(count)d upozorenja. Molimo pregledajte ažurirani sadržaj ispod prije nastavka: %(messages)s" +msgstr "" +"HTML provjera je pokazala %(count)d upozorenja. Molimo pregledajte ažurirani " +"sadržaj ispod prije nastavka: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "tekst" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "formatirani tekst" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "formatirani tekstovi" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "RSS polje se ažurira nekoliko puta dnevno. Promjena u naslovu će biti vidljiva na naslovnici nakon sljedećeg ažuriranja kanala." +msgstr "" +"RSS polje se ažurira nekoliko puta dnevno. Promjena u naslovu će biti " +"vidljiva na naslovnici nakon sljedećeg ažuriranja kanala." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "link" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "pred pripremljen sadržaj" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "zadnji put osvježeno" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "najviše zapisa" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS kanal" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "RSS kanali" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "sekcija" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "sekcije" -#: content/table/models.py:63 -msgid "plain" -msgstr "jednostavno" - -#: content/table/models.py:64 -msgid "title row" -msgstr "naslovni redak" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "naslovni redak i kolona" - -#: content/table/models.py:72 -msgid "table" -msgstr "tablica" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tablice" - -#: content/table/models.py:87 -msgid "data" -msgstr "podaci" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "sadržaj predloška" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "sadržaji predloška" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "predložak" + +#: content/video/models.py:34 msgid "video link" msgstr "link na video" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Polje treba sadržavati link na youtube ili vimeo video, i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Polje treba sadržavati link na youtube ili vimeo video, i.e.: http://www." +"youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "video zapisi" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "poredak" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "etikete" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "jezik" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "prijevod od" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Ostavite ovo prazno za zapise u primarnom jeziku." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "dostupni prijevodi" + +#: module/blog/models.py:33 msgid "published" msgstr "objavljeno" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Ovo se koristi i za generiranu navigaciju." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "objavljeno na" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Biti će automatski postavljeno kada označite `objavljeno` polje iznad." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "članak" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "članci" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "etikete" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "prijevod od" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Ostavite ovo prazno za zapise u primarnom jeziku." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "dostupni prijevodi" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "datum kreiranja" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "datum izmjene" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "tip sadržaja" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "datum objave" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "datum kraja objave" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." -msgstr "Ostavite praznim ukoliko članak treba biti aktivan neograničeno vrijeme." +msgstr "" +"Ostavite praznim ukoliko članak treba biti aktivan neograničeno vrijeme." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "vidljiv od - do" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Objava vezana na datum" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "istaknuti" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Istaknuti" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta ključne riječi" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Ovo će biti dodano predefiniranoj listi ključnih riječi." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta opis" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Ovo će biti dodano predefiniranom opisu." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Optimizacija za tražilice" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Uredi prijevod" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Kreiraj prijevod" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "prijevodi" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." @@ -448,298 +441,339 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Pregled" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "veličina datoteke" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "kreiran" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "tip datoteke" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "informacije o datoteci" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "nadređeni" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "kategorija" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "kategorije" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "autorsko pravo" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Slika" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF dokument" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Tekst" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Formatirani tekst" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binarni" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "opis" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "prijevod medijske datoteke" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "prijevodi medijske datoteke" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "sažetak" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Dodajte kratak sažetak sadržaja ove stranice." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Sažetak" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "navigacijska ekstenzija" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Odaberite modul koji će dostaviti podstranice za ovu stranicu ukoliko je " +"potrebno prilagoditi navigaciju." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "navigacijska ekstenzija" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "u navigaciji" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Odaberite stranice koje trebaju biti navedene kao povezani sadržaj." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Povezane stranice" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "simbolički povezana stranica" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Sav sadržaj je nasljeđen od ove stranice ukoliko je postavljena." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "naslov sadržaja" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "Prva linija je glavni naslov, slijedeće linije su podnaslovi." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "naslov stranice" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Naslov stranice u prozoru browsera. Podrazumijevana vrijednost je jednako " +"kao naslov." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Nazivi" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Ova adresa (URL) je već zauzeta aktivnom stranicom." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Ova adresa (URL) je već zauzeta drugom aktivnom stranicom." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Druge mogućnosti" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "u navigaciji" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Dodaj podređenu stranicu" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Pogledaj na internetnim stranicama" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "naslijeđeno" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "ekstenzije" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "je aktivna" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "aktivan" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Ovo se koristi i za generiranu navigaciju." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "nadjačati URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Nadjačati ciljnu adresu (URL). Budite sigurni da uključite kose crte na početku i kraju ukoliko se odnosi na lokalnu adresu. Ovo se odnosi i na navigaciju i na adrese podstranica" +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Nadjačati ciljnu adresu (URL). Budite sigurni da uključite kose crte na " +"početku i kraju ukoliko se odnosi na lokalnu adresu. Ovo se odnosi i na " +"navigaciju i na adrese podstranica" -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "preusmjeriti na" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "Keširana adresa (URL)" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "stranica" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "stranice" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "sažetak" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Dodajte kratak sažetak sadržaja ove stranice." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Sažetak" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "navigacijska ekstenzija" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Odaberite modul koji će dostaviti podstranice za ovu stranicu ukoliko je potrebno prilagoditi navigaciju." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "navigacijska ekstenzija" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Odaberite stranice koje trebaju biti navedene kao povezani sadržaj." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Povezane stranice" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "simbolički povezana stranica" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Sav sadržaj je nasljeđen od ove stranice ukoliko je postavljena." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "naslov sadržaja" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "Prva linija je glavni naslov, slijedeće linije su podnaslovi." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "naslov stranice" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Naslov stranice u prozoru browsera. Podrazumijevana vrijednost je jednako kao naslov." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Nazivi" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr " Po %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Stvarno izbrisati zapis?" @@ -758,7 +792,8 @@ msgstr "Zapis ne može biti obrisan" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Zapis ne može biti obrisan jer je nadređeni od najmanje jednog drugog zapisa." +msgstr "" +"Zapis ne može biti obrisan jer je nadređeni od najmanje jednog drugog zapisa." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -771,9 +806,8 @@ msgstr "Zaista zamijeniti predložak? <br />Sve izmjene će biti spremljene." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -808,22 +842,24 @@ msgstr "Regija je prazna" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Sadržaj je automatski naslijeđen od nadređene stranice. Ukoliko želite to promjeniti, dodajte neke sadržaje." +msgstr "" +"Sadržaj je automatski naslijeđen od nadređene stranice. Ukoliko želite to " +"promjeniti, dodajte neke sadržaje." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Dodaj novi unos" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Spremi" @@ -851,13 +887,21 @@ msgstr "dolje" msgid "remove" msgstr "izbriši" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Uredi na stranicama" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Home" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -880,29 +924,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Kratice" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Sažmi drvo" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Proširi drvo" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Uredi na stranicama" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " Po %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -946,9 +987,14 @@ msgstr "%(comment_count)s komentara." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s je objavio " +"%(comment_submit_date)s<br />\n" " " -msgstr "\n %(comment_username)s je objavio %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -965,3 +1011,27 @@ msgstr "Potvrdi" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Hvala!" + +#~ msgid "plain" +#~ msgstr "jednostavno" + +#~ msgid "title row" +#~ msgstr "naslovni redak" + +#~ msgid "title row and column" +#~ msgstr "naslovni redak i kolona" + +#~ msgid "table" +#~ msgstr "tablica" + +#~ msgid "tables" +#~ msgstr "tablice" + +#~ msgid "data" +#~ msgstr "podaci" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Ovo će biti dodano predefiniranoj listi ključnih riječi." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Ovo će biti dodano predefiniranom opisu." diff --git a/feincms/locale/it/LC_MESSAGES/django.po b/feincms/locale/it/LC_MESSAGES/django.po index 71688d404..f76e0ec25 100644 --- a/feincms/locale/it/LC_MESSAGES/django.po +++ b/feincms/locale/it/LC_MESSAGES/django.po @@ -1,743 +1,776 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Italian (http://www.transifex.com/projects/p/feincms/language/it/)\n" +"Language-Team: Italian (http://www.transifex.com/projects/p/feincms/language/" +"it/)\n" +"Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "template" - -#: models.py:510 -msgid "ordering" -msgstr "ordinazione" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "lingua" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Tutto" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Parent" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Variazione% s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "Titolo" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "azioni" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "applicazione" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nome" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "e-mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "soggetto" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "contenuto" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "forme di contatto" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "forme di contatto" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "file" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "files" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "image" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "caption" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "immagini" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "Posizione" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "file multimediale" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "file multimediali" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tipo" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "raw contenuti" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "raw contenuti" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "testo" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "rich text" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "Il campo rss viene aggiornato più volte al giorno. Una modifica del titolo sarà visibile solo in home page dopo il prossimo aggiornamento dei mangimi." +msgstr "" +"Il campo rss viene aggiornato più volte al giorno. Una modifica del titolo " +"sarà visibile solo in home page dopo il prossimo aggiornamento dei mangimi." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "collegamento" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "pre-rendering di contenuti" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "Ultimo aggiornamento" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "max. articoli" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS feed" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "Feed RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "sezione" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "sezioni" -#: content/table/models.py:63 -msgid "plain" -msgstr "plain" - -#: content/table/models.py:64 -msgid "title row" -msgstr "titolo di fila" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "riga del titolo e colonna" - -#: content/table/models.py:72 -msgid "table" -msgstr "tavolo" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tavoli" - -#: content/table/models.py:87 -msgid "data" -msgstr "dati" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "template" + +#: content/video/models.py:34 msgid "video link" msgstr "video link" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Questo dovrebbe essere un link ad un video di YouTube o di Vimeo, vale a dire: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Questo dovrebbe essere un link ad un video di YouTube o di Vimeo, vale a " +"dire: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "video" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "ordinazione" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "tags" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "lingua" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "traduzione di" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "" + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "traduzioni disponibili" + +#: module/blog/models.py:33 msgid "published" msgstr "pubblicato" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Questo viene utilizzato per la navigazione generato troppo." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "pubblicato il" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Verrà impostato automaticamente una volta che barrare la casella di controllo `` pubblicato in precedenza." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Verrà impostato automaticamente una volta che barrare la casella di " +"controllo `` pubblicato in precedenza." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "tags" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "traduzione di" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "traduzioni disponibili" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "data di creazione" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "tipi di contenuto" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "data di pubblicazione" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "data fine pubblicazione" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Lasciare vuoto se la voce dovrebbe rimanere attivo per sempre." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "visibile da - a" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta keywords" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Questo sarà anteposto al elenco di parole chiave predefinite." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta description" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Questo sarà anteposto alla descrizione di default." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Modificare la traduzione" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Crea traduzione" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "traduzioni" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Anteprima" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "dimensione del file" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "creato" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "tipo di file" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "file info" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "genitore" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "categorie" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Image" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF document" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Testo" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binary" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "descrizione" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "traduzione di file multimediale" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "traduzioni di file multimediale" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Selezionare il modulo che fornisce sottopagine per questa pagina, se avete " +"bisogno di personalizzare la navigazione." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "in navigazione" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "" + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Tutti i contenuti sono ereditate da questa pagina, se somministrata." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "il titolo del contenuto" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" +"La prima linea è il titolo principale, le seguenti righe sono i sottotitoli." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Titolo della pagina per la finestra del browser. Stesso titolo per " +"impostazione predefinita." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Questo URL è già stato preso da una pagina attiva." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Questo URL è già stato preso da un'altra pagina attiva." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Altre opzioni" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "in navigazione" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Aggiungi pagina figlio" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Vedi sul sito" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "ereditato" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "attiva" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Questo viene utilizzato per la navigazione generato troppo." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "override URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Ignorare l'URL di destinazione. Assicurati di includere le barre all'inizio e alla fine se si tratta di un URL locale. Questo riguarda sia la navigazione e gli URL sottopagine '." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Ignorare l'URL di destinazione. Assicurati di includere le barre all'inizio " +"e alla fine se si tratta di un URL locale. Questo riguarda sia la " +"navigazione e gli URL sottopagine '." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "reindirizzamento" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "Cache URL" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "pagina" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "pagine" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Selezionare il modulo che fornisce sottopagine per questa pagina, se avete bisogno di personalizzare la navigazione." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "" - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Tutti i contenuti sono ereditate da questa pagina, se somministrata." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "il titolo del contenuto" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "La prima linea è il titolo principale, le seguenti righe sono i sottotitoli." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Titolo della pagina per la finestra del browser. Stesso titolo per impostazione predefinita." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "Da %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Cancellare questa voce?" @@ -756,7 +789,8 @@ msgstr "Impossibile eliminare voce" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Impossibile eliminare voce, perché è madre di almeno un altro elemento." +msgstr "" +"Impossibile eliminare voce, perché è madre di almeno un altro elemento." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -769,9 +803,8 @@ msgstr "Davvero cambiare modello? <br /> Tutte le modifiche vengono salvate." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -806,22 +839,24 @@ msgstr "Regione vuota" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Contenuti dal sito padre viene automaticamente ereditate. Per ignorare questo comportamento, aggiungere un po 'di contenuti." +msgstr "" +"Contenuti dal sito padre viene automaticamente ereditate. Per ignorare " +"questo comportamento, aggiungere un po 'di contenuti." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Aggiungi nuovo elemento" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Salvare" @@ -849,13 +884,21 @@ msgstr "giù" msgid "remove" msgstr "rimuovere" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Casa" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -878,29 +921,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Scorciatoie" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtro" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Da %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -944,7 +984,8 @@ msgstr "" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" " " msgstr "" @@ -963,3 +1004,27 @@ msgstr "" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Grazie!" + +#~ msgid "plain" +#~ msgstr "plain" + +#~ msgid "title row" +#~ msgstr "titolo di fila" + +#~ msgid "title row and column" +#~ msgstr "riga del titolo e colonna" + +#~ msgid "table" +#~ msgstr "tavolo" + +#~ msgid "tables" +#~ msgstr "tavoli" + +#~ msgid "data" +#~ msgstr "dati" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Questo sarà anteposto al elenco di parole chiave predefinite." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Questo sarà anteposto alla descrizione di default." diff --git a/feincms/locale/nb/LC_MESSAGES/django.po b/feincms/locale/nb/LC_MESSAGES/django.po index 857e750a3..64115e488 100644 --- a/feincms/locale/nb/LC_MESSAGES/django.po +++ b/feincms/locale/nb/LC_MESSAGES/django.po @@ -1,744 +1,773 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Håvard Grimelid <h@grx.no>, 2011 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Norwegian Bokmål (http://www.transifex.com/projects/p/feincms/language/nb/)\n" +"Language-Team: Norwegian Bokmål (http://www.transifex.com/projects/p/feincms/" +"language/nb/)\n" +"Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: nb\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "mal" - -#: models.py:510 -msgid "ordering" -msgstr "sortering" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "språk" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Alle" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Forelder" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategori" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Endre %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "tittel" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s har blitt flytta til en ny posisjon." -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Forstod ikke flytteinstruksjonen." -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "aktiviteter" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "applikasjonsinnhold" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "applikasjonsinnhold" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "applikasjon" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "på" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Nye kommentarer kan legges til" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "kommentarer" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "offentlig" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "ikke offentlig" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "navn" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "epost" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "tema" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "innhold" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "kontaktskjema" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "kontaktskjemaer" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "fil" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "filer" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "bilde" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "tittel" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "bilder" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "posisjon" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "mediafil" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "mediafiler" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "type" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "råinnhold" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "råinnhold" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Ignorer advarsler fra HTML-validering" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "HTML-validering produserte %(count)d advarsler. Revider oppdatert innhold under før du fortsetter: %(messages)s" +msgstr "" +"HTML-validering produserte %(count)d advarsler. Revider oppdatert innhold " +"under før du fortsetter: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "tekst" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "rik tekst" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "rike tekster" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "RSS-strømmen blir oppdatert flere ganger om dagen. En endring i tittelel vil ikke bli synlig på nettsiden før etter neste oppdatering." +msgstr "" +"RSS-strømmen blir oppdatert flere ganger om dagen. En endring i tittelel vil " +"ikke bli synlig på nettsiden før etter neste oppdatering." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "link" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "forhåndsrendret innhold" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "sist oppdatert" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "maks antall objekter" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS-strøm" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "RSS-strømmer" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "avsnitt" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "avsnitt" -#: content/table/models.py:63 -msgid "plain" -msgstr "enkel" - -#: content/table/models.py:64 -msgid "title row" -msgstr "tittelrad" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "tittelrad og kolonne" - -#: content/table/models.py:72 -msgid "table" -msgstr "tabell" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tabeller" - -#: content/table/models.py:87 -msgid "data" -msgstr "data" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "malinnhold" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "malinnhold" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "mal" + +#: content/video/models.py:34 msgid "video link" msgstr "videolink" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Dette må være en link til en YouTube- eller Vimeo-film. F. eks. http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Dette må være en link til en YouTube- eller Vimeo-film. F. eks. http://www." +"youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "videoer" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "sortering" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "merkelapper" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "språk" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "oversettelse av" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "La denne være tom for innlegg på primærspråket." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "tilgjengelige oversettelser" + +#: module/blog/models.py:33 msgid "published" msgstr "publisert" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Denne vil også bli brukt for navigasjon." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publisert på" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "Blir satt automatisk så snart `publisert`-boksen blir kryssa av." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "innlegg" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "innlegg" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "merkelapper" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "oversettelse av" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "La denne være tom for innlegg på primærspråket." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "tilgjengelige oversettelser" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "opprettet dato" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "endret dato" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "innholdstyper" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "publiseringsdato" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "sluttdato for publisering" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "La denne være tom dersom siden alltid skal være aktiv." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "synlig fra - til" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Datobasert publisering" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "featured" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Featured" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta-nøkkelord" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Dette vil bli lagt inn foran i standard nøkkelord-liste." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta-beskrivelse" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Dette vil bli lagt inn foran standard beskrivelse." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Søkemotoroptimalisering" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Rediger oversettelse" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Lag oversettelse" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "oversettelser" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "" msgstr[1] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Forhåndsvisning" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "filstørrelse" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "opprettet" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "filtype" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "filinfo" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "%d filer importert" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "Ingen inputfil gitt" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "forelder" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "kategori" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "kategorier" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Bilde" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Lyd" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF-dokument" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Tekst" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Rik tekst" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "ZIP-arkiv" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binær" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "beskrivelse" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "mediafil-oversettelse" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "mediafil-oversettelser" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "utdrag" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Legg til et kort sammendrag av innholdet på denne siden." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Utdrag" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "navigasjonsutvidelse" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Velg modulen som skal bidra med undersider til denne siden dersom du trenger " +"å tilpasse navigasjonen." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Navigasjonsutvidelse" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "i navigasjon" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Velg sidene som skal listes som relatert innhold." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Relaterte sider" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "symbolsk linket side" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Dersom gitt, blir alt innhold blir arvet fra denne siden." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "innholdstittel" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "Første linje er hovedtittelen, følgende linjer er undertitler." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "sidetittel" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "Sidetittel for nettleservinduet. Samme som tittel som standard." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Titler" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Denne URL-en er allerede i bruk av en aktiv side." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Denne URL-en er allerede i bruk av annen en aktiv side." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Andre valg" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "i navigasjon" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Legg til underside" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Vis på nettsted" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "arvet" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "utvidelser" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "er aktiv" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "aktiv" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Denne vil også bli brukt for navigasjon." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "overstyr URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Overstyr mål-URL. Inkluder skråstrek ved starten og ved slutten dersom det er en lokal URL. Dette gjelder både for navigasjons- og underside-URL-er." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Overstyr mål-URL. Inkluder skråstrek ved starten og ved slutten dersom det " +"er en lokal URL. Dette gjelder både for navigasjons- og underside-URL-er." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "videresend til" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "Mellomlagret URL" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "side" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "sider" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "utdrag" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Legg til et kort sammendrag av innholdet på denne siden." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Utdrag" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "navigasjonsutvidelse" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Velg modulen som skal bidra med undersider til denne siden dersom du trenger å tilpasse navigasjonen." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Navigasjonsutvidelse" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Velg sidene som skal listes som relatert innhold." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Relaterte sider" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "symbolsk linket side" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Dersom gitt, blir alt innhold blir arvet fra denne siden." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "innholdstittel" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "Første linje er hovedtittelen, følgende linjer er undertitler." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "sidetittel" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Sidetittel for nettleservinduet. Samme som tittel som standard." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Titler" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "For %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Slette objektet?" @@ -757,7 +786,8 @@ msgstr "Kan ikke slette objekt" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Kan ikke slette objektet fordi det er foreldre til minst ett annet objekt." +msgstr "" +"Kan ikke slette objektet fordi det er foreldre til minst ett annet objekt." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -770,9 +800,8 @@ msgstr "Endre mal? <br />Alle endringer blir lagret." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -807,22 +836,24 @@ msgstr "Tom region" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Innhold fra forelder-side blir arvet automatisk. Overstyr dette ved å legge til innhold." +msgstr "" +"Innhold fra forelder-side blir arvet automatisk. Overstyr dette ved å legge " +"til innhold." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Legg til nytt objekt" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Lagre" @@ -850,13 +881,21 @@ msgstr "ned" msgid "remove" msgstr "fjern" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Rediger på nettsted" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Hjem" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -879,29 +918,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Snarveier" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Slå sammen tre" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Utvid tre" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Rediger på nettsted" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "For %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -945,9 +981,14 @@ msgstr "%(comment_count)s kommentarer." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s sa på %(comment_submit_date)s<br /" +">\n" " " -msgstr "\n %(comment_username)s sa på %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -964,3 +1005,27 @@ msgstr "Send inn" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Takk!" + +#~ msgid "plain" +#~ msgstr "enkel" + +#~ msgid "title row" +#~ msgstr "tittelrad" + +#~ msgid "title row and column" +#~ msgstr "tittelrad og kolonne" + +#~ msgid "table" +#~ msgstr "tabell" + +#~ msgid "tables" +#~ msgstr "tabeller" + +#~ msgid "data" +#~ msgstr "data" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Dette vil bli lagt inn foran i standard nøkkelord-liste." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Dette vil bli lagt inn foran standard beskrivelse." diff --git a/feincms/locale/nl/LC_MESSAGES/django.po b/feincms/locale/nl/LC_MESSAGES/django.po index 56b8a811e..aa036021d 100644 --- a/feincms/locale/nl/LC_MESSAGES/django.po +++ b/feincms/locale/nl/LC_MESSAGES/django.po @@ -1,744 +1,785 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # bjornpost <bjorn.post@gmail.com>, 2013 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Dutch (http://www.transifex.com/projects/p/feincms/language/nl/)\n" +"Language-Team: Dutch (http://www.transifex.com/projects/p/feincms/language/" +"nl/)\n" +"Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "template" - -#: models.py:510 -msgid "ordering" -msgstr "volgorde" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "taal" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Alle" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Ouder" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categorie" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "%s veranderen" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "titel" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +#, fuzzy +#| msgid "You don't have the necessary permissions to edit this object" +msgid "You do not have permission to modify this object" +msgstr "Je hebt niet de juiste rechten om dit object aan te passen" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s is verplaatst." -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Begreep verplaats instructie niet" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "acties" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." +#: admin/tree_editor.py:552 +#, fuzzy, python-format +#| msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "%s items succesvol verwijderd." -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "Geselecteerde %(verbose_name_plural)s verwijderen" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "applicatie content" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "applicatie contents" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "applicatie" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "actief" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Nieuwe reacties kunnen worden toegevoegd" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "reacties" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "gedeeld" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "niet gedeeld" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "naam" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "e-Mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "onderwerp" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "inhoud" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "contactformulier" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "contactformulieren" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "bestand" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "bestanden" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "afbeelding" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "alternatieve tekst" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "Omschrijving van de afbeelding" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "onderschrift" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "afbeeldingen" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "positie" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "formaat" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "media-bestand" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "media-bestanden" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "type" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "Ruwe Inhoud" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "ruwe inhoud" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Negeer de HTML validatie waarschuwingen" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "HTML validatie leverde %(count)d waarschuwingen op. Kijk alsjeblieft de bijgewerkte content na voordat je verder gaat: %(messages)s" +msgstr "" +"HTML validatie leverde %(count)d waarschuwingen op. Kijk alsjeblieft de " +"bijgewerkte content na voordat je verder gaat: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "tekst" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "opgemaakte tekst" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "opgemaakte teksten" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "Het RSS veld wordt meerdere malen per dag geactualiseerd. Een verandering in de titel zal pas op de pagina verschijnen na de volgende update." +msgstr "" +"Het RSS veld wordt meerdere malen per dag geactualiseerd. Een verandering in " +"de titel zal pas op de pagina verschijnen na de volgende update." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "Link" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "Vooraf-gerenderde Inhoud" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "Laatste update" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "Maximaal aantal" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS feed" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "RSS feeds" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "sectie" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "secties" -#: content/table/models.py:63 -msgid "plain" -msgstr "plat" - -#: content/table/models.py:64 -msgid "title row" -msgstr "titel rij" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "title rij en kolom" - -#: content/table/models.py:72 -msgid "table" -msgstr "tabel" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tabellen" - -#: content/table/models.py:87 -msgid "data" -msgstr "data" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "template content" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "template contents" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "template" + +#: content/video/models.py:34 msgid "video link" msgstr "video link" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Dit moet een link naar een youtube of vimeo video zijn. Bijvoorbeeld: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Dit moet een link naar een youtube of vimeo video zijn. Bijvoorbeeld: http://" +"www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "videos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "Taggen" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "volgorde" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "tags" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "taal" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "vertaling van" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Laat dit veld leeg voor bijdragen in de hoofd-taal." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "Beschikbare vertalingen" + +#: module/blog/models.py:33 msgid "published" msgstr "gepubliceerd" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Dit wordt ook gebruikt voor de gegenereerde navigatie." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "gepubliceerd op" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Wordt automatisch eenmalig ingesteld zodra `gepubliceerd` aangevinkt is." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Wordt automatisch eenmalig ingesteld zodra `gepubliceerd` aangevinkt is." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "item" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "items" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "tags" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "vertaling van" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Laat dit veld leeg voor bijdragen in de hoofd-taal." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "Beschikbare vertalingen" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "gemaakt op" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "laatst gewijzigd op" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "content types" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "gepubliceerd op" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "gepubliceerd tot" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Leeglaten als het item voor altijd actief moet blijven." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "zichtbaar van - tot" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Datum-gebaseerde publicering" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "aanbevolen" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Aanbevolen" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta trefwoorden" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Deze begrippen worden voor in de standaard trefwoordenlijst ingevoegd." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta beschrijving" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Deze beschrijving wordt voor in de standaard beschrijving ingevoegd." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Zoekmachine optimalisatie" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Wijzig vertaling" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Maak vertaling" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "vertalingen" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "Dit zou een oneindige lus maken in de hiërarchie" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "Kan niet overschrijven met ander bestandstype (poging tot overschrijven van %(old_ext)s met %(new_ext)s)" +msgstr "" +"Kan niet overschrijven met ander bestandstype (poging tot overschrijven van " +"%(old_ext)s met %(new_ext)s)" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "%(count)d media file succesvol toegevoegd aan %(category)s" msgstr[1] "%(count)d media files succesvol toegevoegd aan %(category)s" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "Voeg geselecteerde media files toe aan categorie" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "ZIP-bestand geexporteerd als %s" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "ZIP-bestand export mislukt: %s" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "Exporteer geselecteerde mediabestanden als ZIP-bestand" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Voorbeeld" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "bestandsgrootte" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "gemaakt" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "bestandstype" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "bestandsinformatie" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "%d bestanden geïmporteerd" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "Importeren van ZIP-bestand mislukt: %s" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "Geen inputbestand opgegeven" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "ouder" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "categorie" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "categorieën" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Afbeelding" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF document" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Tekst" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Opgemaakte Tekst" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "Zip-archief" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binaire data" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "omschrijving" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "Mediabestand-vertaling" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "Mediabestand-vertalingen" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "samenvatting" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" +"Voeg een korte samenvatting toe die de inhoud van deze pagina beschrijft." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Samenvatting" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "navigatie-uitbreiding" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Kies de module die subpagina's voor deze pagina definieert als je de " +"navigatie wilt uitbreiden." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Navigatie-uitbreiding" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "in navigatie" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Selecteer pagina's die beschouwd moet worden als gerelateerd aan deze." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Gerelateerde pagina's" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "Site" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "verbonden pagina" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "" +"Als dit ingesteld is, dan wordt de inhoud geleverd door de aangegeven pagina." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "content titel" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" +"De eerste regel is de hoofd-titel, de overige regels vormen de ondertitel." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "paginatitel" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "paginatitel voor het browservenster. Standaard gelijk aan de titel." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Titels" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Deze URL is al in gebruik door een actieve pagina." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Deze URL is al in gebruik door een andere actieve pagina." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Overige opties" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "in navigatie" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Voeg subpagina toe" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Op de website bekijken" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." -msgstr "De inhoud van de originele vertaling is gekopieerd naar de aangemaakte pagina." +msgstr "" +"De inhoud van de originele vertaling is gekopieerd naar de aangemaakte " +"pagina." -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "Je hebt niet de juiste rechten om dit object aan te passen" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "geërfd" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "uitbreidingen" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "is actief" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "actief" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Dit wordt ook gebruikt voor de gegenereerde navigatie." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "overschrijf URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Overschrijft de URL. Als het een lokale URL betreft moet er aan aan weerszijden een / staan. Dit veld heeft betrekking op zowel de navigatie als de URLs van subpagina's." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Overschrijft de URL. Als het een lokale URL betreft moet er aan aan " +"weerszijden een / staan. Dit veld heeft betrekking op zowel de navigatie " +"als de URLs van subpagina's." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "doorsturen naar" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "URL uit cache" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "pagina" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "pagina's" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "samenvatting" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Voeg een korte samenvatting toe die de inhoud van deze pagina beschrijft." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Samenvatting" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "navigatie-uitbreiding" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Kies de module die subpagina's voor deze pagina definieert als je de navigatie wilt uitbreiden." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Navigatie-uitbreiding" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Selecteer pagina's die beschouwd moet worden als gerelateerd aan deze." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Gerelateerde pagina's" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "Site" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "verbonden pagina" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Als dit ingesteld is, dan wordt de inhoud geleverd door de aangegeven pagina." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "content titel" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "De eerste regel is de hoofd-titel, de overige regels vormen de ondertitel." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "paginatitel" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "paginatitel voor het browservenster. Standaard gelijk aan de titel." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Titels" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr " Op %(filter_title)s" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Item echt verwijderen?" @@ -757,7 +798,9 @@ msgstr "Kan item niet verwijderen" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Kan item niet verwijderen, omdat het de ouder is van een of meerdere sub-items." +msgstr "" +"Kan item niet verwijderen, omdat het de ouder is van een of meerdere sub-" +"items." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -770,10 +813,12 @@ msgstr "Template echt veranderen?<br />Alle wijzigingen zijn opgeslagen." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." -msgstr "Template echt veranderen? <br />Alle wijzigingen zijn opgeslagen en de inhoud van <strong>%%(source_regions)s</strong>is verplaatst naar <strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +msgstr "" +"Template echt veranderen? <br />Alle wijzigingen zijn opgeslagen en de " +"inhoud van <strong>%%(source_regions)s</strong>is verplaatst naar <strong>" +"%%(target_region)s</strong>." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -807,22 +852,24 @@ msgstr "Leeg gebied" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Inhoud van de ouder-pagina wordt automatisch geërfd. Voeg zelf inhoud toe om dit te veranderen." +msgstr "" +"Inhoud van de ouder-pagina wordt automatisch geërfd. Voeg zelf inhoud toe om " +"dit te veranderen." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Nieuw item toevoegen" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "Voeg nog een %(verbose_name)s toe" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "Verwijder" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Opslaan" @@ -850,13 +897,21 @@ msgstr "naar onder" msgid "remove" msgstr "verwijderen" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Op de website wijzigen" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Startpagina" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Voeg toe" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -879,29 +934,26 @@ msgstr "Herstel %(verbose_name)s" msgid "Press the save button below to revert to this version of the object." msgstr "Druk op de save-knop om deze versie van het object te herstellen." -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Snelkoppelingen" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Alles dichtklappen" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Alles openklappen" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filter" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Op de website wijzigen" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Voeg toe" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " Op %(filter_title)s" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -914,7 +966,8 @@ msgstr "Selecteer categorie om toe te passen:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "De volgende mediabestanden worden toegevoegd aan de geselecteerde categorie:" +msgstr "" +"De volgende mediabestanden worden toegevoegd aan de geselecteerde categorie:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -945,9 +998,14 @@ msgstr "%(comment_count)s reacties" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s zei op %(comment_submit_date)s<br /" +">\n" " " -msgstr "\n %(comment_username)s zei op %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -964,3 +1022,29 @@ msgstr "Verzenden" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Bedankt!" + +#~ msgid "plain" +#~ msgstr "plat" + +#~ msgid "title row" +#~ msgstr "titel rij" + +#~ msgid "title row and column" +#~ msgstr "title rij en kolom" + +#~ msgid "table" +#~ msgstr "tabel" + +#~ msgid "tables" +#~ msgstr "tabellen" + +#~ msgid "data" +#~ msgstr "data" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "" +#~ "Deze begrippen worden voor in de standaard trefwoordenlijst ingevoegd." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "" +#~ "Deze beschrijving wordt voor in de standaard beschrijving ingevoegd." diff --git a/feincms/locale/pl/LC_MESSAGES/django.po b/feincms/locale/pl/LC_MESSAGES/django.po index 4645e1b89..fff700744 100644 --- a/feincms/locale/pl/LC_MESSAGES/django.po +++ b/feincms/locale/pl/LC_MESSAGES/django.po @@ -1,446 +1,437 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # areksz <arkadiusz.szczur@gmail.com>, 2013 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Polish (http://www.transifex.com/projects/p/feincms/language/pl/)\n" +"Language-Team: Polish (http://www.transifex.com/projects/p/feincms/language/" +"pl/)\n" +"Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pl\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "szablon" - -#: models.py:510 -msgid "ordering" -msgstr "sortowanie" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "język" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "wszystko" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Rodzic" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategoria" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Zmień %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "tytuł" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +#, fuzzy +#| msgid "You don't have the necessary permissions to edit this object" +msgid "You do not have permission to modify this object" +msgstr "Nie masz wystarczających uprawnień aby edytować ten element" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s został przesunięty" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Instrukcja przesunięcia nie jest zrozumiała." -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "akcje" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "zawartość aplikacji" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "application content" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplikacja" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "aktywny" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Nowe komentarze mogą być dodane" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "komentarze" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "publiczne" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "nie publiczne" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nazwa" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "email" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "temat" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "zawartość" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "formularz kontaktowy" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "formularze kontaktowe" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "plik" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "pliki" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "zdjęcie" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "zdjęcia" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "pozycja" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "plik media" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "pliki media" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "typ" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "tekst niesformatowany" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "teksty niesformatowane" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Ignoruj ostrzeżenia o walidacji HMTL" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "tekst" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "Obszar tekstowy (WYSIWYG)" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "Obszary tekstowe (WYSIWYG)" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." msgstr "" -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "link" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "ostatnio aktualizowany" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "maksymalna ilość" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "kanał RSS" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "kanały RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "sekcja" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "sekcje" -#: content/table/models.py:63 -msgid "plain" -msgstr "zwyczajny" - -#: content/table/models.py:64 -msgid "title row" -msgstr "tytuł" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "" - -#: content/table/models.py:72 -msgid "table" -msgstr "tablica" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tablice" - -#: content/table/models.py:87 -msgid "data" -msgstr "data" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "tekst szablonu" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "teksty szablonów" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "szablon" + +#: content/video/models.py:34 msgid "video link" msgstr "link video" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Umieść link do youtube.com lub vimeo.com, np. http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Umieść link do youtube.com lub vimeo.com, np. http://www.youtube.com/watch?" +"v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "video" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "sortowanie" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "tagi" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "język" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "tłumaczenie" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "" + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "dostępne tłumaczenia" + +#: module/blog/models.py:33 msgid "published" msgstr "opublikowany" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "" -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "opublikowany na" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Zostanie automatycznie ustawione po kliknięciu \"opublikowany\" powyżej" +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Zostanie automatycznie ustawione po kliknięciu \"opublikowany\" powyżej" -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "wpis" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "wpisy" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "tagi" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "tłumaczenie" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "dostępne tłumaczenia" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "data utworzenia" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "data modyfikacji" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "typ treści" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "data publikacji" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "końcowa data publikacji" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Pozostaw puste jeśli nie chcesz określać końcowej daty publikacji" -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "widoczne od - do" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Określanie okresu publikacji" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "wyróżniony" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "tagi meta - keywords" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Zostanie dołączone z przodu listy tagów" +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "tagi meta - description" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Zostanie dołączone z przodu listy tagów" +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Pola SEO " -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Edytuj tłumaczenie" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Stwórz tłumaczenie" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "tłumaczenia" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." @@ -448,298 +439,328 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "Dodaj zaznaczone pliki do kategorii" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Podgląd" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "rozmiar pliku" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "utworzony" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "typ pliku" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "informacje o pliku" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "zaimportowano %d plików" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "Brak wybranego pliku " -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "rodzic" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug (wyświetlany adres)" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "kategoria" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "kategorie" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Zdjęcie" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Audio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "Dokument PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Tekst" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Obszar tekstowy (WYSIWYG)" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "Archiwum ZIP" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binarny" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "opis" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "W menu" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "" + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Powiązane strony" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "Strony" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "dowiązana strona" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "" + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "Tytuł treści" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "Tytuł strony" + +#: module/page/extensions/titles.py:30 +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Tytuły" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "ten URL jest już używany przez aktywną stronę." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "ten URL jest już używany przez inną aktywną stronę." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Pozostałe opcje" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "W menu" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Dodaj podstronę" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Zobacz podgląd strony" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "Nie masz wystarczających uprawnień aby edytować ten element" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "dziedziczone" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "rozszerzenia" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "czy jest aktywne" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "aktywny" -#: module/page/models.py:175 +#: module/page/models.py:173 +msgid "This title is also used for navigation menu items." +msgstr "" + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "nadpisz URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." msgstr "" -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "przekieruj do" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "strona" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "strony" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "" - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "" - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Powiązane strony" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "Strony" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "dowiązana strona" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "" - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "Tytuł treści" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "" - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "Tytuł strony" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "" - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Tytuły" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "Po %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Usunąć?" @@ -758,7 +779,9 @@ msgstr "Brak możliwości usunięcia elementu" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Element nie może zostać usunięty ponieważ zawiera przynajmniej jeden element podrzędny. Usuń wpierw elementy podrzędne." +msgstr "" +"Element nie może zostać usunięty ponieważ zawiera przynajmniej jeden element " +"podrzędny. Usuń wpierw elementy podrzędne." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -771,9 +794,8 @@ msgstr "Zmienić szablon? <br />Wszystkie zmiany zostały zachowane." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -808,22 +830,24 @@ msgstr "Pusty region" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Treść ze strony nadrzędnej został automatycznie odziedziczony. Wstaw treść aby nadpisać odziedziczoną wartość." +msgstr "" +"Treść ze strony nadrzędnej został automatycznie odziedziczony. Wstaw treść " +"aby nadpisać odziedziczoną wartość." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Dodaj nowy element" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "Dodaj następny %(verbose_name)s" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "Usuń" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Zachowaj" @@ -851,13 +875,21 @@ msgstr "dół" msgid "remove" msgstr "usuń" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Edytuj na stronie" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Główna" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Dodaj" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -880,29 +912,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Zwiń drzewo" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Rozwiń drzewo" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtruj" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Edytuj na stronie" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Dodaj" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Po %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -946,7 +975,8 @@ msgstr "" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" " " msgstr "" @@ -965,3 +995,24 @@ msgstr "Wyślij" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Dziękuję!" + +#~ msgid "plain" +#~ msgstr "zwyczajny" + +#~ msgid "title row" +#~ msgstr "tytuł" + +#~ msgid "table" +#~ msgstr "tablica" + +#~ msgid "tables" +#~ msgstr "tablice" + +#~ msgid "data" +#~ msgstr "data" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Zostanie dołączone z przodu listy tagów" + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Zostanie dołączone z przodu listy tagów" diff --git a/feincms/locale/pt/LC_MESSAGES/django.po b/feincms/locale/pt/LC_MESSAGES/django.po index 72e91b7cb..46674dcf0 100644 --- a/feincms/locale/pt/LC_MESSAGES/django.po +++ b/feincms/locale/pt/LC_MESSAGES/django.po @@ -1,744 +1,786 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Vítor Figueiró <vfigueiro@gmail.com>, 2012 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Portuguese (http://www.transifex.com/projects/p/feincms/language/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.com/projects/p/feincms/" +"language/pt/)\n" +"Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "modelo" - -#: models.py:510 -msgid "ordering" -msgstr "ordenação" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "idioma" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Todos" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Ascendente" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "título" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +#, fuzzy +#| msgid "You don't have the necessary permissions to edit this object" +msgid "You do not have permission to modify this object" +msgstr "Não possui as permissões necessárias para editar este objecto" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s foi movido para uma nova posição" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "A instrução para mover não foi entendida." -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "acções" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." -msgstr "" +#: admin/tree_editor.py:552 +#, fuzzy, python-format +#| msgid "Successfully added %(count)d media file to %(category)s." +#| msgid_plural "Successfully added %(count)d media files to %(category)s." +msgid "Successfully deleted %(count)d items." +msgstr "%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "conteúdo de aplicação" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "conteúdos de aplicação" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplicação" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "habilitado" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Podem ser adicionados novos comentários" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "comentários" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "público" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "não público" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nome" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "e-mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "assunto" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "conteúdo" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "formulário de contacto" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "formulários de contacto" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "ficheiro" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "ficheiros" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "imagem" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "texto alternativo" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "Descrição da imagem" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "legenda" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "imagens" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "posição" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "formato" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "ficheiro multimédia" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "ficheiros multimédia" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tipo" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "conteúdo cru" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "conteúdos crus" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Ignorar os avisos de validação do HTML" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo actualizado em baixo antes de continuar: %(messages)s " +msgstr "" +"A validação do HTML produziu %(count)d avisos. Por favor reveja o conteúdo " +"actualizado em baixo antes de continuar: %(messages)s " -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "texto" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "textos ricos" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só aparece no site após a actualização do feed RSS seguinte." +msgstr "" +"O feed RSS é actualizado várias vezes ao dia. Uma alteração do título só " +"aparece no site após a actualização do feed RSS seguinte." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "ligação" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "conteúdo pré-renderizado" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "última actualização" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "número máximo" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "feed RSS" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "feed RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "secção" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "secções" -#: content/table/models.py:63 -msgid "plain" -msgstr "simples" - -#: content/table/models.py:64 -msgid "title row" -msgstr "linha de título" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "linha e coluna de título" - -#: content/table/models.py:72 -msgid "table" -msgstr "tabela" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tabelas" - -#: content/table/models.py:87 -msgid "data" -msgstr "dados" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "conteúdo do modelo" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "conteúdos de template" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "modelo" + +#: content/video/models.py:34 msgid "video link" msgstr "ligação de vídeo" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: " "http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Isto deve ser uma ligação para um vídeo do Youtube ou do vimeo, p.ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "vídeo" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "vídeos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "Tagging" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "ordenação" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "etiquetas" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "idioma" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "tradução de" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Deixe este campo em branco nas entradas no idioma original." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "traduções disponíveis" + +#: module/blog/models.py:33 msgid "published" msgstr "publicado" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Isto também é usado para a navegação gerada automaticamente." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publicado em" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Será definido automaticamente quando activar a caixa de verificação 'publicado' acima." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Será definido automaticamente quando activar a caixa de verificação " +"'publicado' acima." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "entrada" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "entradas" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "etiquetas" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "tradução de" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Deixe este campo em branco nas entradas no idioma original." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "traduções disponíveis" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "data de criação" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "data de modificação" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "tipos de conteúdo" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "data de publicação" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "publicar até" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Deixe vazio se a entrada deve permanecer activa para sempre." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "visível de - até" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Publicação baseada em datas" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "em destaque" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Em destaque" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "palavras-chave meta" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Isto será inserido antes da lista de palavras-chave padrão." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "descrição meta" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Isto será inserido antes da descrição padrão." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Optimização para motor de busca" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Editar a tradução" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Criar tradução" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "traduções" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "Isto criaria um ciclo na hierarquia" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "Não é possível sobrescrever com um tipo de ficheiro diferente (tentativa de substituir um %(old_ext)s com um %(new_ext)s)" +msgstr "" +"Não é possível sobrescrever com um tipo de ficheiro diferente (tentativa de " +"substituir um %(old_ext)s com um %(new_ext)s)" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." -msgstr[0] "%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." -msgstr[1] "%(count)d ficheiros multimédia adicionados com sucesso a %(category)s." +msgstr[0] "" +"%(count)d ficheiro multimédia adicionado com sucesso a %(category)s." +msgstr[1] "" +"%(count)d ficheiros multimédia adicionados com sucesso a %(category)s." -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "Adicionar os ficheiros multimédia seleccionados à categoria" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "Ficheiro ZIP exportado como %s" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "A exportação do ficheiro ZIP falhou: %s" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "Exportar os ficheiros multimédia seleccionados como ficheiro zip" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Antevisão" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "tamanho do ficheiro" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "criado em" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "tipo de ficheiro" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "informação do ficheiro" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "%d ficheiros importados" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "A importação do ficheiro ZIP falhou: %s" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "Não indicou o ficheiro de origem" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "ascendente" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "categorias" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Imagem" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Áudio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "Documento PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Texto" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Texto Rico" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "Ficheiro zip" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binário" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "descrição" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "tradução do ficheiro multimédia" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "traduções do ficheiro multimédia" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "excerto" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Adicione um breve excerto que resuma o conteúdo desta página." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Excerto" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "extensão de navegação" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Seleccione o módulo que providencia as sub-páginas, caso necessite de " +"personalizar a navegação." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Extensão de navegação" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "na navegação" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Seleccione páginas a listar como conteúdo relacionado." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Páginas relacionadas" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "Site" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "página ligada" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "O conteúdo é herdado desta página." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "título do conteúdo" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" +"A primeira linha é o título principal. Outras linhas serão sub-títulos." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "título da página" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Título da página para a janela do navegador. Se omitido assume o título." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Títulos" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Este URL já está tomado por uma página activa." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Este URL já está tomado por uma outra página activa." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "outras opções" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "na navegação" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Adicionar página descendente" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Ver no site" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." -msgstr "O conteúdo da tradução original foi copiado para a página recém-criada." +msgstr "" +"O conteúdo da tradução original foi copiado para a página recém-criada." -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "Não possui as permissões necessárias para editar este objecto" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "herdado" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "extensões" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "activo" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "activo" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Isto também é usado para a navegação gerada automaticamente." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "URL efectivo" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "URL efectivo. Deve conter uma / no início e no fim, caso se trate de um URL local. Este campo determina a navegação e os URL's das sub-páginas." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"URL efectivo. Deve conter uma / no início e no fim, caso se trate de um URL " +"local. Este campo determina a navegação e os URL's das sub-páginas." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "redireccionar para" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "URL em cache" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "página" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "páginas" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "excerto" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Adicione um breve excerto que resuma o conteúdo desta página." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Excerto" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "extensão de navegação" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Seleccione o módulo que providencia as sub-páginas, caso necessite de personalizar a navegação." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Extensão de navegação" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Seleccione páginas a listar como conteúdo relacionado." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Páginas relacionadas" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "Site" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "página ligada" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "O conteúdo é herdado desta página." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "título do conteúdo" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "A primeira linha é o título principal. Outras linhas serão sub-títulos." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "título da página" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Título da página para a janela do navegador. Se omitido assume o título." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Títulos" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "Por %(filter_title)s" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Confirma a eliminação do item?" @@ -765,14 +807,14 @@ msgstr "Alterar o modelo" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." -msgstr "Confirma a alteração do modelo? <br />Todas as alterações serão guardadas." +msgstr "" +"Confirma a alteração do modelo? <br />Todas as alterações serão guardadas." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -813,16 +855,16 @@ msgstr "O conteúdo é herdado da página ascendente, excepto se o indicar aqui. msgid "Add new item" msgstr "Adicionar novo item" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "Adicionar outro %(verbose_name)s" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "Remover" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Guardar" @@ -850,13 +892,21 @@ msgstr "para baixo" msgid "remove" msgstr "remover" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Editar no site" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Página inicial" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Adicionar" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -864,7 +914,8 @@ msgstr "Recuperar %(verbose_name)s excluído" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "Clique no botão 'Guardar' em baixo para recuperar esta versão do objecto." +msgstr "" +"Clique no botão 'Guardar' em baixo para recuperar esta versão do objecto." #: templates/admin/feincms/revision_form.html:12 msgid "History" @@ -877,31 +928,29 @@ msgstr "Reverter %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "Clique no botão 'Guardar' em baixo para reverter para esta versão do objecto." +msgstr "" +"Clique no botão 'Guardar' em baixo para reverter para esta versão do objecto." -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Atalhos" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Colapsar a árvore" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Expandir a árvore" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Editar no site" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Adicionar" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Por %(filter_title)s" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -914,7 +963,8 @@ msgstr "Seleccione a categoria a aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "Os seguintes ficheiros multimédia serão adicionados à categoria seleccionada:" +msgstr "" +"Os seguintes ficheiros multimédia serão adicionados à categoria seleccionada:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -945,9 +995,14 @@ msgstr "%(comment_count)s comentários." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s disse em " +"%(comment_submit_date)s<br />\n" " " -msgstr "\n %(comment_username)s disse em %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -964,3 +1019,27 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Obrigado!" + +#~ msgid "plain" +#~ msgstr "simples" + +#~ msgid "title row" +#~ msgstr "linha de título" + +#~ msgid "title row and column" +#~ msgstr "linha e coluna de título" + +#~ msgid "table" +#~ msgstr "tabela" + +#~ msgid "tables" +#~ msgstr "tabelas" + +#~ msgid "data" +#~ msgstr "dados" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Isto será inserido antes da lista de palavras-chave padrão." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Isto será inserido antes da descrição padrão." diff --git a/feincms/locale/pt_BR/LC_MESSAGES/django.po b/feincms/locale/pt_BR/LC_MESSAGES/django.po index d876a2baa..6b2e73258 100644 --- a/feincms/locale/pt_BR/LC_MESSAGES/django.po +++ b/feincms/locale/pt_BR/LC_MESSAGES/django.po @@ -1,744 +1,784 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Guilherme Gondim <semente+transifex@taurinus.org>, 2012 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/feincms/language/pt_BR/)\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/" +"feincms/language/pt_BR/)\n" +"Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "modelo" - -#: models.py:510 -msgid "ordering" -msgstr "ordenação" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "idioma" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Todos" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Ascendente" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Categoria" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "título" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +#, fuzzy +#| msgid "You don't have the necessary permissions to edit this object" +msgid "You do not have permission to modify this object" +msgstr "Você não tem as permissões necessárias para editar este objeto" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s foi movido para uma nova posição." -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "A instrução para mover não foi entendida." -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "ações" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." -msgstr "" +#: admin/tree_editor.py:552 +#, fuzzy, python-format +#| msgid "Successfully added %(count)d media file to %(category)s." +#| msgid_plural "Successfully added %(count)d media files to %(category)s." +msgid "Successfully deleted %(count)d items." +msgstr "Adicionado com sucesso %(count)d arquivo de mídia em %(category)s." -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "conteúdo de aplicação" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "conteúdos de aplicação" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplicação" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "habilitado" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Podem ser adicionados novos comentários" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "comentários" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "público" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "não público" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nome" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "e-mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "assunto" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "conteúdo" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "formulário de contato" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "formulários de contato" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "arquivo" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "arquivos" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "imagem" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "legenda" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "imagens" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "posição" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "arquivo de mídia" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "arquivos de mídia" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tipo" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "conteúdo cru" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "conteúdos crus" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "Ignorar os avisos de validação HTML" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "A validação HTML produziu %(count)d avisos. Por favor, revise o conteúdo atualizado abaixo antes de continuar: %(messages)s" +msgstr "" +"A validação HTML produziu %(count)d avisos. Por favor, revise o conteúdo " +"atualizado abaixo antes de continuar: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "texto" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "texto rico" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "textos ricos" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "O feed RSS é atualizado por várias vezes ao dia. Uma alteração do título só será visível na página após a próxima atualização do feed." +msgstr "" +"O feed RSS é atualizado por várias vezes ao dia. Uma alteração do título só " +"será visível na página após a próxima atualização do feed." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "ligação" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "conteúdo pré-renderizado" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "última atualização" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "número máximo" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "feed RSS" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "feeds RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "seção" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "seções" -#: content/table/models.py:63 -msgid "plain" -msgstr "simples" - -#: content/table/models.py:64 -msgid "title row" -msgstr "linha de título" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "linha e coluna de título" - -#: content/table/models.py:72 -msgid "table" -msgstr "tabela" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tabelas" - -#: content/table/models.py:87 -msgid "data" -msgstr "dados" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "conteúdo de modelo" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "conteúdos de modelo" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "modelo" + +#: content/video/models.py:34 msgid "video link" msgstr "ligação de vídeo" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Isto deve ser uma ligação para um vídeo do Youtube ou Vimeo, i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Isto deve ser uma ligação para um vídeo do Youtube ou Vimeo, i.e.: http://" +"www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "vídeo" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "vídeos" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "ordenação" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "etiquetas" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "idioma" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "tradução de" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Deixe este campo em branco para entradas no idioma original." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "traduções disponíveis" + +#: module/blog/models.py:33 msgid "published" msgstr "publicado" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Isto também é usado para a navegação gerada automaticamente." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publicado em" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Será definido automaticamente assim que você ativar a caixa `publicado` acima." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Será definido automaticamente assim que você ativar a caixa `publicado` " +"acima." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "entrada" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "entradas" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "etiquetas" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "tradução de" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Deixe este campo em branco para entradas no idioma original." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "traduções disponíveis" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "data de criação" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "data de modificação" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "tipos de conteúdo" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "Otimização para motores de busca" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "publicar até" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Deixe em branco se a entrada deve ficar ativa para sempre." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "visível de - até" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Publicação baseada em datas" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "recomendado" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Recomendado" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta palavras-chave" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Isto será inserido antes da lista de palavras-chave padrão." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta descrição" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Isto será inserido antes da descrição padrão." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Otimização para motores de busca" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Editar a tradução" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Criar tradução" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "traduções" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "Adicionado com sucesso %(count)d arquivo de mídia em %(category)s." msgstr[1] "Adicionado com sucesso %(count)d arquivos de mídia em %(category)s." -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "Adicionar arquivos de mídia selecionados à categoria" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Pré-visualização" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "tamanho do arquivo" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "criado em" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "tipo de arquivo" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "informação do arquivo" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "%d arquivos importados" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "Nenhum arquivo de entrada fornecido" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "ascendente" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "categoria" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "categorias" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Imagem" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Vídeo" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Áudio" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "documento PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Texto" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Texto Rico" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "Arquivo ZIP" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binário" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "descrição" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "tradução do arquivo de mídia" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "traduções do arquivo de mídia" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "trecho" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Adicione um breve trecho que sumarize o conteúdo desta página." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Trecho" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "extensão de navegação" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Selecione o módulo que fornece sub-páginas para esta página se você precisa " +"personalizar a navegação." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Extensão de navegação" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "na navegação" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Selecione as páginas que devam ser listadas como conteúdo relacionado." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Páginas relacionadas" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "Site" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "página de ligação" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "O conteúdo é herdado desta página, se fornecida." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "título do conteúdo" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "" +"A primeira linha é o título principal, as linhas subsequentes são sub-" +"títulos." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "título da página" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Título da página para a janela do navegador. Por padrão, o mesmo que o " +"título." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Títulos" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Esta URL já está ocupada por uma página ativa." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Esta URL já está ocupada por outra página ativa." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Outras opções" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "na navegação" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Adicionar página descendente" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Ver no site" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "Você não tem as permissões necessárias para editar este objeto" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "herdado" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "extensões" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "ativo" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "ativo" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Isto também é usado para a navegação gerada automaticamente." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "URL efetiva" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Substitui a URL de destino. Certifique-se de incluir barras no início e no final, se for uma URL local. Isso afeta tanto a navegação e URLs de subpáginas." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Substitui a URL de destino. Certifique-se de incluir barras no início e no " +"final, se for uma URL local. Isso afeta tanto a navegação e URLs de " +"subpáginas." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "redirecionar para" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "URL em cache" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "página" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "páginas" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "trecho" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Adicione um breve trecho que sumarize o conteúdo desta página." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Trecho" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "extensão de navegação" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Selecione o módulo que fornece sub-páginas para esta página se você precisa personalizar a navegação." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Extensão de navegação" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "Selecione as páginas que devam ser listadas como conteúdo relacionado." - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "Páginas relacionadas" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "Site" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "página de ligação" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "O conteúdo é herdado desta página, se fornecida." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "título do conteúdo" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "A primeira linha é o título principal, as linhas subsequentes são sub-títulos." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "título da página" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Título da página para a janela do navegador. Por padrão, o mesmo que o título." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Títulos" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr " Por %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Confirma a remoção do item?" @@ -765,14 +805,14 @@ msgstr "Alterar o modelo" #: templates/admin/feincms/_messages_js.html:8 msgid "Really change template? <br />All changes are saved." -msgstr "Confirma a alteração do modelo? <br />Todas as alterações serão salvas." +msgstr "" +"Confirma a alteração do modelo? <br />Todas as alterações serão salvas." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -807,22 +847,24 @@ msgstr "Região vazia" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "O conteúdo é herdado automaticamente da página ascendente. Para mudar este comportamento, adicione algum conteúdo." +msgstr "" +"O conteúdo é herdado automaticamente da página ascendente. Para mudar este " +"comportamento, adicione algum conteúdo." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Adicionar novo item" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "Adicionar mais um %(verbose_name)s" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "Remover" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Guardar" @@ -850,13 +892,21 @@ msgstr "para baixo" msgid "remove" msgstr "remover" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Editar no site" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Página inicial" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Adicionar" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -864,7 +914,8 @@ msgstr "Recuperar %(verbose_name)s removido" #: templates/admin/feincms/recover_form.html:17 msgid "Press the save button below to recover this version of the object." -msgstr "Pressione o botão de salvar abaixo para recuperar esta versão do objeto." +msgstr "" +"Pressione o botão de salvar abaixo para recuperar esta versão do objeto." #: templates/admin/feincms/revision_form.html:12 msgid "History" @@ -877,31 +928,29 @@ msgstr "Reverter %(verbose_name)s" #: templates/admin/feincms/revision_form.html:24 msgid "Press the save button below to revert to this version of the object." -msgstr "Pressione o botão de salvar abaixo para reverter para esta versão do objeto." +msgstr "" +"Pressione o botão de salvar abaixo para reverter para esta versão do objeto." -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Atalhos" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Contrair árvore" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Expandir árvore" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtrar" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Editar no site" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Adicionar" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " Por %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -914,7 +963,8 @@ msgstr "Selecione a categoria a aplicar:" #: templates/admin/medialibrary/add_to_category.html:17 msgid "The following media files will be added to the selected category:" -msgstr "Os seguintes arquivos de mídia serão adicionados à categoria selecionada:" +msgstr "" +"Os seguintes arquivos de mídia serão adicionados à categoria selecionada:" #: templates/admin/medialibrary/add_to_category.html:22 msgid "Add to category" @@ -945,9 +995,14 @@ msgstr "%(comment_count)s comentários." #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s disse em " +"%(comment_submit_date)s<br />\n" " " -msgstr "\n %(comment_username)s disse em %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -964,3 +1019,27 @@ msgstr "Enviar" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Obrigado!" + +#~ msgid "plain" +#~ msgstr "simples" + +#~ msgid "title row" +#~ msgstr "linha de título" + +#~ msgid "title row and column" +#~ msgstr "linha e coluna de título" + +#~ msgid "table" +#~ msgstr "tabela" + +#~ msgid "tables" +#~ msgstr "tabelas" + +#~ msgid "data" +#~ msgstr "dados" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Isto será inserido antes da lista de palavras-chave padrão." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Isto será inserido antes da descrição padrão." diff --git a/feincms/locale/ro/LC_MESSAGES/django.po b/feincms/locale/ro/LC_MESSAGES/django.po index 60c3517bd..594d17e0e 100644 --- a/feincms/locale/ro/LC_MESSAGES/django.po +++ b/feincms/locale/ro/LC_MESSAGES/django.po @@ -1,446 +1,438 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Gabriel Kovacs <kovacs.gabi@gmail.com>, 2010 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Romanian (http://www.transifex.com/projects/p/feincms/language/ro/)\n" +"Language-Team: Romanian (http://www.transifex.com/projects/p/feincms/" +"language/ro/)\n" +"Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ro\n" -"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" - -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "șablon" - -#: models.py:510 -msgid "ordering" -msgstr "ordonare" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?" +"2:1));\n" -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "limbă" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Modifică %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "titlu" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +msgid "You do not have permission to modify this object" +msgstr "" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "acțiuni" -#: admin/tree_editor.py:432 +#: admin/tree_editor.py:552 #, python-format -msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "" -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "conținutul aplicației" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "conținuturile aplicației" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "aplicație" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "nume" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "e-mail" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "subiect" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "conținut" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "formular de contact" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "formulare de contact" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "fișier" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "fișiere" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "imagine" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "legendă" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "imagini" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "poziție" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "fișier media" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "fișiere media" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tip" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "conținut neformatat" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "conținuturi neformatate" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "text" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "text formatabil" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "texte formatabile" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "Fluxul RSS este actualizat de mai multe ori pe zi. O modificare a titlului va fi vizibilă in prima pagină după următoarea actualizare a fluxului." +msgstr "" +"Fluxul RSS este actualizat de mai multe ori pe zi. O modificare a titlului " +"va fi vizibilă in prima pagină după următoarea actualizare a fluxului." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "legătură" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "conținut predefinit" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "ultima actualizare" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "nr. de obiecte maxime" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "flux RSS" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "fluxuri RSS" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "" -#: content/table/models.py:63 -msgid "plain" -msgstr "simplu" - -#: content/table/models.py:64 -msgid "title row" -msgstr "titlu" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "titlu rând și coloană" - -#: content/table/models.py:72 -msgid "table" -msgstr "tabel" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tabele" - -#: content/table/models.py:87 -msgid "data" -msgstr "data" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "șablon" + +#: content/video/models.py:34 msgid "video link" msgstr "legătură film" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Aceasta ar trebui să fie o legătură către un film de pe youtube sau vimeo, de ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Aceasta ar trebui să fie o legătură către un film de pe youtube sau vimeo, " +"de ex.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "film" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "filme" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "ordonare" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "etichete" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "limbă" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "tradus de" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "" + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "traduceri disponibile" + +#: module/blog/models.py:33 msgid "published" msgstr "publicat" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Aceasta este deasemenea folosită pentru navigarea generată." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "publicat la" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Va fi trimis automat în momentul in care bifați butonul `publicat` de mai sus." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Va fi trimis automat în momentul in care bifați butonul `publicat` de mai " +"sus." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "înregistrare" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "înregistrari" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "etichete" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "tradus de" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "traduceri disponibile" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "data creerii" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "data modificării" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "data publicării" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "sfârșitul publicării" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Lasă gol dacă înregistrarea ar trebui să fie activă întotdeauna" -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "vizibil de la - până la" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "cuvinte cheie meta" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Va fi inserat la lista predefinită de cuvinte cheie." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "descriere meta" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Va fi inserată la descrierea predefinită." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Modifică translatarea" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Creează o translatare" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "translații" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." @@ -448,298 +440,338 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Pre-vizualizare" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "creat" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "tipul fișierului" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "părinte" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "categorie" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "categorii" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "copyright" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "Imagine" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "document PDF" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Text" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binar" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "descriere" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "traducere fișier media" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "traduceri fișier media" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "navigare extinsă" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Selectați modulul care furnizează subpaginile pentru această pagină dacă " +"doriți să personalizaţi." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "în navigare" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "" + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "legătură pagină" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Întreg conținutul este moștenit de la această pagină daca se dorește." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "titlu conținut" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "Prima linie reprezintă titlul principal, următoarele sunt subtitluri." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "titlul paginii" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Titlul paginii pentru fereastra navigatorului. Implicit este la fel cu " +"titlul paginii." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Acest URL este deja rezervat de către o pagină activă." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Acest URL este deja rezervat de către o altă pagină activă." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Alte opțiuni" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "în navigare" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Adaugă o pagină copil" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Vezi pe site" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "moștenit" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "extensii" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "activ" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Aceasta este deasemenea folosită pentru navigarea generată." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "suprascrie URL" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Suprascrie URL-ul țintă. Aveți grijă să scrieti / la început și la șfârșit dacă este un URL local.Aceasta afectează atât navigația cât și subpaginile." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Suprascrie URL-ul țintă. Aveți grijă să scrieti / la început și la șfârșit " +"dacă este un URL local.Aceasta afectează atât navigația cât și subpaginile." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "redirecționare către" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "URL în cache" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "pagină" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "pagini" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "" - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "navigare extinsă" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Selectați modulul care furnizează subpaginile pentru această pagină dacă doriți să personalizaţi." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "" - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "legătură pagină" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Întreg conținutul este moștenit de la această pagină daca se dorește." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "titlu conținut" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "Prima linie reprezintă titlul principal, următoarele sunt subtitluri." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "titlul paginii" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Titlul paginii pentru fereastra navigatorului. Implicit este la fel cu titlul paginii." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "După %(filter_title)s" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Confirmți ștergerea obiectului?" @@ -758,7 +790,9 @@ msgstr "Nu pot șterge obiectul" #: templates/admin/feincms/_messages_js.html:6 msgid "Cannot delete item, because it is parent of at least one other item." -msgstr "Nu se poate șterge obiectul, deoarece este părinte la cel puțin incă un obiect." +msgstr "" +"Nu se poate șterge obiectul, deoarece este părinte la cel puțin incă un " +"obiect." #: templates/admin/feincms/_messages_js.html:7 msgid "Change template" @@ -771,9 +805,8 @@ msgstr "Doriți ștergerea șablonului? <br />Toate modificarile au fost salvate #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -808,22 +841,24 @@ msgstr "Regiunea este goală" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Conținutul de la pagina părinte este moștenită automat. Pentru a suprascrie acest lucru, adăugați conținut" +msgstr "" +"Conținutul de la pagina părinte este moștenită automat. Pentru a suprascrie " +"acest lucru, adăugați conținut" #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Adaugă un obiect nou" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Salvează" @@ -851,13 +886,21 @@ msgstr "jos" msgid "remove" msgstr "scoate" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Acasă" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -880,29 +923,26 @@ msgstr "" msgid "Press the save button below to revert to this version of the object." msgstr "" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Scurtături" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Închide arborele" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Deschide arborele" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtrează" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "După %(filter_title)s" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -946,7 +986,8 @@ msgstr "" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" " " msgstr "" @@ -965,3 +1006,27 @@ msgstr "Trimite" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Mulțumesc!" + +#~ msgid "plain" +#~ msgstr "simplu" + +#~ msgid "title row" +#~ msgstr "titlu" + +#~ msgid "title row and column" +#~ msgstr "titlu rând și coloană" + +#~ msgid "table" +#~ msgstr "tabel" + +#~ msgid "tables" +#~ msgstr "tabele" + +#~ msgid "data" +#~ msgstr "data" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Va fi inserat la lista predefinită de cuvinte cheie." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Va fi inserată la descrierea predefinită." diff --git a/feincms/locale/ru/LC_MESSAGES/django.po b/feincms/locale/ru/LC_MESSAGES/django.po index ef920ccd0..575bd8faa 100644 --- a/feincms/locale/ru/LC_MESSAGES/django.po +++ b/feincms/locale/ru/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-05-22 20:55-0500\n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" "Language-Team: Russian (http://www.transifex.com/projects/p/feincms/language/" @@ -21,19 +21,6 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: models.py:390 content/template/models.py:63 -msgid "template" -msgstr "шаблон" - -#: models.py:538 -msgid "ordering" -msgstr "сортировка" - -#: translations.py:282 module/blog/extensions/translations.py:25 -#: module/extensions/translations.py:140 -msgid "language" -msgstr "язык" - #: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Все" @@ -47,45 +34,45 @@ msgstr "Родитель" msgid "Category" msgstr "Категория" -#: admin/item_editor.py:189 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Изменить %s" -#: admin/tree_editor.py:293 content/rss/models.py:23 -#: content/section/models.py:35 module/blog/models.py:34 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 #: module/medialibrary/models.py:45 module/page/models.py:172 #: module/page/models.py:240 msgid "title" msgstr "заголовок" -#: admin/tree_editor.py:352 admin/tree_editor.py:369 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 msgid "You do not have permission to modify this object" msgstr "У вас нет прав для изменения этого объекта" -#: admin/tree_editor.py:486 +#: admin/tree_editor.py:491 msgid "No permission" msgstr "Нет прав" -#: admin/tree_editor.py:504 +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "Узел \"%s\" был перемещен на новое место." -#: admin/tree_editor.py:507 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Перемещение не удалось. Непонятная команда." -#: admin/tree_editor.py:518 +#: admin/tree_editor.py:523 msgid "actions" msgstr "действия" -#: admin/tree_editor.py:541 +#: admin/tree_editor.py:552 #, fuzzy, python-format msgid "Successfully deleted %(count)d items." msgstr "Успешно удалено %s объектов" -#: admin/tree_editor.py:554 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "Удалить выбранные %(verbose_name_plural)s" @@ -102,23 +89,23 @@ msgstr "Данные приложений" msgid "application" msgstr "приложение" -#: content/comments/models.py:31 +#: content/comments/models.py:32 msgid "enabled" msgstr "включены" -#: content/comments/models.py:32 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Новые комментарии могут быть добавлены" -#: content/comments/models.py:36 content/comments/models.py:37 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "комментарии" -#: content/comments/models.py:59 +#: content/comments/models.py:60 msgid "public" msgstr "Опубликовано" -#: content/comments/models.py:60 +#: content/comments/models.py:61 msgid "not public" msgstr "Не опубликовано" @@ -218,8 +205,9 @@ msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" msgstr "" -"HTML валидация вызвала %(count)d предупреждений. Пожалуйста просмотрите ниже обновленное " -"содержимое прежде чем продолжить: %(messages)s" +"HTML валидация вызвала %(count)d предупреждений. Пожалуйста просмотрите ниже " +"обновленное содержимое прежде чем продолжить: %(messages)s" + #: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "текст" @@ -239,6 +227,7 @@ msgid "" msgstr "" "RSS поле обновляется несколько раз в день. Изменение в названии будет видно " "на главной странице только после следующего обновления фида" + #: content/rss/models.py:28 msgid "link" msgstr "ссылка" @@ -279,6 +268,10 @@ msgstr "содержимое шаблона" msgid "template contents" msgstr "содержимое шаблонов" +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "шаблон" + #: content/video/models.py:34 msgid "video link" msgstr "ссылка на видео" @@ -303,36 +296,19 @@ msgstr "видео" msgid "Tagging" msgstr "Теггирование" -#: module/blog/models.py:32 -msgid "published" -msgstr "опубликовано" - -#: module/blog/models.py:35 -msgid "This is used for the generated navigation too." -msgstr "Используется также в сгенерированно навигации." - -#: module/blog/models.py:39 -msgid "published on" -msgstr "опубликовано" - -#: module/blog/models.py:41 -msgid "Will be set automatically once you tick the `published` checkbox above." -msgstr "" -"Будет установлено автоматически, как только Вы отметите пункт \"опубликовано" -"\" выше." - -#: module/blog/models.py:47 -msgid "entry" -msgstr "запись" - -#: module/blog/models.py:48 -msgid "entries" -msgstr "записи" +#: models.py:550 +msgid "ordering" +msgstr "сортировка" #: module/blog/extensions/tags.py:17 msgid "tags" msgstr "теги" +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "язык" + #: module/blog/extensions/translations.py:35 #: module/extensions/translations.py:148 msgid "translation of" @@ -348,6 +324,32 @@ msgstr "Оставьте поле пустым для записей на осн msgid "available translations" msgstr "доступные переводы" +#: module/blog/models.py:33 +msgid "published" +msgstr "опубликовано" + +#: module/blog/models.py:36 +msgid "This is used for the generated navigation too." +msgstr "Используется также в сгенерированно навигации." + +#: module/blog/models.py:40 +msgid "published on" +msgstr "опубликовано" + +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Будет установлено автоматически, как только Вы отметите пункт \"опубликовано" +"\" выше." + +#: module/blog/models.py:48 +msgid "entry" +msgstr "запись" + +#: module/blog/models.py:49 +msgid "entries" +msgstr "записи" + #: module/extensions/changedate.py:41 msgid "creation date" msgstr "дата создания" @@ -405,29 +407,30 @@ msgid "" "This text is displayed on the search results page. It is however not used " "for the SEO ranking. Text longer than 140 characters is truncated." msgstr "" -"Этот текст отображается в выдаче поисковиков. Но оно не используется " -"для SEO ранжирования. Текст длиннее 140 символов усекается." +"Этот текст отображается в выдаче поисковиков. Но оно не используется для SEO " +"ранжирования. Текст длиннее 140 символов усекается." + #: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "SEO Оптимизация" -#: module/extensions/translations.py:239 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Изменить перевод" -#: module/extensions/translations.py:246 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Создать перевод" -#: module/extensions/translations.py:254 +#: module/extensions/translations.py:264 msgid "translations" msgstr "переводы" -#: module/medialibrary/forms.py:28 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "Это создало бы зацикливание в иерархии" -#: module/medialibrary/forms.py:72 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " @@ -435,6 +438,7 @@ msgid "" msgstr "" "Невозможно перезаписать с различным типом файла (попытка перезаписать " "%(old_ext)s с %(new_ext)s)" + #: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." @@ -576,15 +580,103 @@ msgstr "перевод медиа-файла" msgid "media file translations" msgstr "переводы медиа-файлов" -#: module/page/forms.py:186 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "отрывок" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Добавьте краткий отрывок резюмируя содержание" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Отрывок" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "расширение навигации" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Выберите модуль который обеспечит подстраницы для этой страницы, если вам " +"нужно настроитьнавигацию." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Расширение навигации" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "в навигации" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "Выберите страницы, которые должны быть отображены как похожие." + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "Похожие страницы" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "Сайт" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "страница привязанная символической ссылкой" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Все содержимое наследуется с этой страницы." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "Заголовок содержимого" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "Первая строка — основной заголовок, следующие строки — подзаголовки." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "заголовок страницы" + +#: module/page/extensions/titles.py:30 +#, fuzzy +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Заголовок страницы для окна браузера. По умолчанию = просто заголовку " +"страницы." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Заголовки" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Этот URL уже занят активной страницей." -#: module/page/forms.py:205 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Этот URL уже занят другой активной страницей." -#: module/page/forms.py:210 +#: module/page/forms.py:211 msgid "This page does not allow attachment of child pages" msgstr "Эта страница не позволяет создание дочерних страниц" @@ -615,8 +707,8 @@ msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -"Содержание на языке по-умолчанию было скопировано в свежесозданную " -"страницу." +"Содержание на языке по-умолчанию было скопировано в свежесозданную страницу." + #: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "Вы не имеете необходимые права на изменение этого объекта" @@ -656,15 +748,17 @@ msgid "" "the end if it is a local URL. This affects both the navigation and subpages' " "URLs." msgstr "" -"Переопределение целевой URL. Не забудьте добавить слэш в начале и в " -"конце, если это локальный URL. Это влияет на навигацию и URL дочерних страниц." +"Переопределение целевой URL. Не забудьте добавить слэш в начале и в конце, " +"если это локальный URL. Это влияет на навигацию и URL дочерних страниц." + #: module/page/models.py:190 msgid "redirect to" msgstr "редирект на" #: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." -msgstr "Целевой URL для автоматических переадресации или первичный ключ страницы." +msgstr "" +"Целевой URL для автоматических переадресации или первичный ключ страницы." #: module/page/models.py:196 msgid "Cached URL" @@ -685,84 +779,6 @@ msgstr "страница" msgid "pages" msgstr "страницы" -#: module/page/extensions/excerpt.py:18 -msgid "excerpt" -msgstr "отрывок" - -#: module/page/extensions/excerpt.py:21 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Добавьте краткий отрывок резюмируя содержание" - -#: module/page/extensions/excerpt.py:25 -msgid "Excerpt" -msgstr "Отрывок" - -#: module/page/extensions/navigation.py:86 -#: module/page/extensions/navigation.py:115 -msgid "navigation extension" -msgstr "расширение навигации" - -#: module/page/extensions/navigation.py:119 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "" -"Выберите модуль который обеспечит подстраницы для этой страницы, если вам нужно настроить" -"навигацию." -#: module/page/extensions/navigation.py:134 -msgid "Navigation extension" -msgstr "Расширение навигации" - -#: module/page/extensions/relatedpages.py:21 -msgid "Select pages that should be listed as related content." -msgstr "Выберите страницы, которые должны быть отображены как похожие." - -#: module/page/extensions/relatedpages.py:26 -msgid "Related pages" -msgstr "Похожие страницы" - -#: module/page/extensions/sites.py:21 -msgid "Site" -msgstr "Сайт" - -#: module/page/extensions/symlinks.py:22 -msgid "symlinked page" -msgstr "страница привязанная символической ссылкой" - -#: module/page/extensions/symlinks.py:23 -msgid "All content is inherited from this page if given." -msgstr "Все содержимое наследуется с этой страницы." - -#: module/page/extensions/titles.py:19 -msgid "content title" -msgstr "Заголовок содержимого" - -#: module/page/extensions/titles.py:22 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "Первая строка — основной заголовок, следующие строки — подзаголовки." - -#: module/page/extensions/titles.py:26 -msgid "page title" -msgstr "заголовок страницы" - -#: module/page/extensions/titles.py:30 -#, fuzzy -msgid "" -"Page title for browser window. Same as title bydefault. Must not be longer " -"than 70 characters." -msgstr "" -"Заголовок страницы для окна браузера. По умолчанию = просто заголовку " -"страницы." - -#: module/page/extensions/titles.py:60 -msgid "Titles" -msgstr "Заголовки" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr " По %(filter_title)s " - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Вы уверены, что хотите удалить элемент?" @@ -833,8 +849,9 @@ msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." msgstr "" -"Контент автоматически унаследован от родительского узла. Чтобы переопределить это" -"поведение, добавьте содержимое." +"Контент автоматически унаследован от родительского узла. Чтобы " +"переопределить этоповедение, добавьте содержимое." + #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Добавить элемент" @@ -876,13 +893,21 @@ msgstr "вниз" msgid "remove" msgstr "удалить" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Редактировать на сайте" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Начало" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Добавить" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -921,13 +946,10 @@ msgstr "Развернуть" msgid "Filter" msgstr "Фильтр" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Редактировать на сайте" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Добавить" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " По %(filter_title)s " #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 diff --git a/feincms/locale/tr/LC_MESSAGES/django.po b/feincms/locale/tr/LC_MESSAGES/django.po index 52b458529..eb8a8e7c1 100644 --- a/feincms/locale/tr/LC_MESSAGES/django.po +++ b/feincms/locale/tr/LC_MESSAGES/django.po @@ -1,745 +1,782 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # byzgl <forumicin85@gmail.com>, 2013 # byzgl <forumicin85@gmail.com>, 2013 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Turkish (http://www.transifex.com/projects/p/feincms/language/tr/)\n" +"Language-Team: Turkish (http://www.transifex.com/projects/p/feincms/language/" +"tr/)\n" +"Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: tr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "tema" - -#: models.py:510 -msgid "ordering" -msgstr "sıralama" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "dil" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "Tümü" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "Üst Öğe" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "Kategori" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "Değişiklik %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "başlık" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +#, fuzzy +#| msgid "You don't have the necessary permissions to edit this object" +msgid "You do not have permission to modify this object" +msgstr "Bu nesneye düzenlemek için gerekli izinleriniz yok" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s yeni bir pozisyona taşındı." -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "Taşıma yönergeleri anlaşılamadı." -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "olaylar" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." +#: admin/tree_editor.py:552 +#, fuzzy, python-format +#| msgid "Successfully deleted %s items." +msgid "Successfully deleted %(count)d items." msgstr "%s öğeleri başarıyla silindi." -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "%(verbose_name_plural)s seçilenleri sil" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "uygulama içeriği" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "uygulama içerikleri" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "uygulama" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "etkin" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "Yeni yorumlar eklenebilir" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "yorumlar" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "genel" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "genel değil" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "ad" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "email" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "konu" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "içerik" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "iletişim formu" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "iletişim formları" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "dosya" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "dosyalar" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "resim" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "alternatif yazı" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "Resim açıklaması" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "altyazı" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "resimler" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "pozisyon" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "format" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "medya dosyası" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "medya dosyaları" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "tür" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "ham içerik" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "ham içerikler" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Toparla" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "HTML doğrulama uyarılarını yoksay" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "HTML doğrulama işlemi %(count)d uyarı. Devam etmeden önce aşağıdaki güncellenen içeriği gözden geçirin: %(messages)s" +msgstr "" +"HTML doğrulama işlemi %(count)d uyarı. Devam etmeden önce aşağıdaki " +"güncellenen içeriği gözden geçirin: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "yazı" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "zengin yazı" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "zengin yazı" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." -msgstr "Rss alanı günde birkaç kez güncellenir. Başlıktaki bir değişiklik sadece bir sonraki besleme güncellemesinden sonra ana sayfasında görülebilir." +msgstr "" +"Rss alanı günde birkaç kez güncellenir. Başlıktaki bir değişiklik sadece bir " +"sonraki besleme güncellemesinden sonra ana sayfasında görülebilir." -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "link" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "önden görüntülenen içerik" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "son güncelleme" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "max. öğe" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS besleme" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "RSS beslemeler" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "bölüm" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "bölümler" -#: content/table/models.py:63 -msgid "plain" -msgstr "düz" - -#: content/table/models.py:64 -msgid "title row" -msgstr "başlık satırı" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "başlık satır ve sütunu" - -#: content/table/models.py:72 -msgid "table" -msgstr "tablo" - -#: content/table/models.py:73 -msgid "tables" -msgstr "tablolar" - -#: content/table/models.py:87 -msgid "data" -msgstr "veri" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "tema içeriği" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "tema içerikleri" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "tema" + +#: content/video/models.py:34 msgid "video link" msgstr "video linki" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "Bu, bir youtube veya vimeo video bir bağlantı olmalıdır, ör: http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"Bu, bir youtube veya vimeo video bir bağlantı olmalıdır, ör: http://www." +"youtube.com/watch?v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "video" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "vidyolar" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "Etiketleme" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "sıralama" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "etiketler" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "dil" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "tercümesi" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "Ana dilde girişler için boş bırakın." + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "kullanılabilir çeviriler" + +#: module/blog/models.py:33 msgid "published" msgstr "yayınlandı" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "Bu da oluşturulan navigasyon için kullanılır." -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "yayınlanan tarih" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." -msgstr "Yukarıdaki `yayınlanan` onay kutusunu bir kez işaretleyin otomatik olarak ayarlanır." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." +msgstr "" +"Yukarıdaki `yayınlanan` onay kutusunu bir kez işaretleyin otomatik olarak " +"ayarlanır." -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "giriş" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "girişler" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "etiketler" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "tercümesi" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "Ana dilde girişler için boş bırakın." - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "kullanılabilir çeviriler" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "oluşturulma tarihi" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "düzenlenme tarihi" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "içerik tipleri" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "yayın tarihi" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "yayın bitiş tarihi" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "Giriş sonsuza kadar aktif kalmalı ise boş bırakın." -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "için - görünür " -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "Tarih-bazlı yayınlama" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "öne çıkan" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "Öne çıkan" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta anahtar kelimeler" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "Bu, varsayılan anahtar kelime listesine başına eklenecektir." +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta açıklaması" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "Bu varsayılan açıklamanın başına eklenecektir." +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "Arama motoru optimizasyonu" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "Çeviriyi düzemle" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "Çeviri oluştur" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "çeviriler" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "Bu hiyerarşi içinde bir döngü yaratacak" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" -msgstr "Farklı dosya türü (%(old_ext)s ile bir %(new_ext)s üzerine yazma girişimi) ile üzerine yazamazsınız" +msgstr "" +"Farklı dosya türü (%(old_ext)s ile bir %(new_ext)s üzerine yazma girişimi) " +"ile üzerine yazamazsınız" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "%(count)d medya dosyaları %(category)s e başarıyla eklendi." msgstr[1] "%(count)d medya dosyaları %(category)s e başarıyla eklendi." -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "Seçilen medya dosyalarını kategoriye ekle" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "ZIP dosyası %s olarak dışa aktarıldı" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "ZIP dosyasını %s olarak dışa aktarmada hata" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "Seçilen medya dosyalarını ZIP dosyası olarak dışa aktar" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "Önizleme" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "dosya boyutu" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "oluşturuldu" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "dosya tipi" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "dosya bilgisi" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "%d dosya içe aktarıldı" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "ZIP dosyasını %s olarak içe aktarmada hata" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "Dosya girdisi yok" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "üst öğe" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "kurşun" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "kategori" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "kategoriler" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "telif hakkı" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "resim" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "Video" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "Ses" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF dökümanı" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "Yazı" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "Zengin Yazı" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "Zip arşivi" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "Binary" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "açıklama" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "medya dosyası çevirisi" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "medya dosyası çevirileri" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "alıntı" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "Bu sayfanın içeriğini özetleyen kısa bir alıntı ekleyin." + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "Alıntı" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "navigasyon bileşeni" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "" +"Navigasyonu özelleştirmeniz gerekiyorsa, bu altsayfaları sağlayan modülü " +"seçiniz." + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "Navigasyon bileşeni" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "navigasyonda" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "İlişkili içerik olarak listelenecek sayfaları seçiniz" + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "İlgili sayfalar" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "Site" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "Sembolik olarak bağlanmış sayfa" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "Verilirse tüm içerik bu sayfadan devralınır." + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "içerik başlığı" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "İlk satır ana başlık, aşağıdaki satırlar ise alt başlıktır." + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "sayfa başlığı" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "" +"Tarayıcı penceresi için sayfa başlığı. Varsayılan olarak başlık ile aynı." + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "Başlıklar" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "Bu URL aktif bir sayfa tarafından alınmış." -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "Bu URL zaten başka aktif bir sayfa tarafından alınmış." -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "Diğer seçenekler" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "navigasyonda" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "Alt sayfa ekle" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "Sitede göster" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "Orijinal çeviri içeriği yeni oluşturulan sayfaya kopyalandı." -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "Bu nesneye düzenlemek için gerekli izinleriniz yok" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "devralındı" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "bileşenler" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "aktif" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "aktif" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "Bu da oluşturulan navigasyon için kullanılır." + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "URL geçersiz" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "Hedef URL geçersiz Yerel bir URL ise başında ve sonunda bölü eklemeyi unutmayın. Bu navigasyon ve alt sayfaları etkiler." +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"Hedef URL geçersiz Yerel bir URL ise başında ve sonunda bölü eklemeyi " +"unutmayın. Bu navigasyon ve alt sayfaları etkiler." -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "buraya yönlendiriliyor" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "Önbelleklenmiş URL" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "sayfa" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "sayfalar" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "alıntı" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "Bu sayfanın içeriğini özetleyen kısa bir alıntı ekleyin." - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "Alıntı" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "navigasyon bileşeni" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "Navigasyonu özelleştirmeniz gerekiyorsa, bu altsayfaları sağlayan modülü seçiniz." - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "Navigasyon bileşeni" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "İlişkili içerik olarak listelenecek sayfaları seçiniz" - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "İlgili sayfalar" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "Site" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "Sembolik olarak bağlanmış sayfa" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "Verilirse tüm içerik bu sayfadan devralınır." - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "içerik başlığı" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "İlk satır ana başlık, aşağıdaki satırlar ise alt başlıktır." - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "sayfa başlığı" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "Tarayıcı penceresi için sayfa başlığı. Varsayılan olarak başlık ile aynı." - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "Başlıklar" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "%(filter_title)s ile" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "Gerçekten öğe silisin mi?" @@ -771,10 +808,12 @@ msgstr "Tema değiştirilsin mi? <br /> Tüm değişiklikler kaydedildi." #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." -msgstr "Gerçekten tema değişsin mi? <br />Tüm değişiklikler kaydedildi ve <strong>%%(source_regions)s</strong> teki içerikler <strong>%%(target_region)s</strong> e taşındı." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." +msgstr "" +"Gerçekten tema değişsin mi? <br />Tüm değişiklikler kaydedildi ve <strong>" +"%%(source_regions)s</strong> teki içerikler <strong>%%(target_region)s</" +"strong> e taşındı." #: templates/admin/feincms/_messages_js.html:12 msgid "Hide" @@ -808,22 +847,24 @@ msgstr "Bölge boş" msgid "" "Content from the parent site is automatically inherited. To override this " "behaviour, add some content." -msgstr "Üst siteden içerik otomatik devralınır. Bu davranışı geçersiz kılmak için, bazı içerikler ekleyin." +msgstr "" +"Üst siteden içerik otomatik devralınır. Bu davranışı geçersiz kılmak için, " +"bazı içerikler ekleyin." #: templates/admin/feincms/content_editor.html:33 msgid "Add new item" msgstr "Yeni öğe ekle" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "Başka ekle %(verbose_name)s" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "Kaldır" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "Kaydet" @@ -851,13 +892,21 @@ msgstr "aşağı" msgid "remove" msgstr "kaldır" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "Sitede düzenle" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "Anasayfa" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "Ekle" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -880,29 +929,26 @@ msgstr "Dön %(verbose_name)s" msgid "Press the save button below to revert to this version of the object." msgstr "Nesnenin bu sürümüne dönmek için aşağıdaki kaydet düğmesine basın." -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "Kısayollar" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "Ağacı daralt" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "Ağacı genişlet" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "Filtre" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "Sitede düzenle" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "Ekle" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "%(filter_title)s ile" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -946,9 +992,14 @@ msgstr "%(comment_count)s yorum" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s dedi buna " +"%(comment_submit_date)s<br />\n" " " -msgstr "\n %(comment_username)s dedi buna %(comment_submit_date)s<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -965,3 +1016,27 @@ msgstr "Gönder" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "Teşekkürler!" + +#~ msgid "plain" +#~ msgstr "düz" + +#~ msgid "title row" +#~ msgstr "başlık satırı" + +#~ msgid "title row and column" +#~ msgstr "başlık satır ve sütunu" + +#~ msgid "table" +#~ msgstr "tablo" + +#~ msgid "tables" +#~ msgstr "tablolar" + +#~ msgid "data" +#~ msgstr "veri" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "Bu, varsayılan anahtar kelime listesine başına eklenecektir." + +#~ msgid "This will be prepended to the default description." +#~ msgstr "Bu varsayılan açıklamanın başına eklenecektir." diff --git a/feincms/locale/zh_CN/LC_MESSAGES/django.po b/feincms/locale/zh_CN/LC_MESSAGES/django.po index d732c1914..7ad192d53 100644 --- a/feincms/locale/zh_CN/LC_MESSAGES/django.po +++ b/feincms/locale/zh_CN/LC_MESSAGES/django.po @@ -1,744 +1,772 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # aaffdd11 <chenyuan328@gmail.com>, 2011 # indexofire <indexofire@gmail.com>, 2011 msgid "" msgstr "" "Project-Id-Version: FeinCMS\n" -"Report-Msgid-Bugs-To: http://github.com/feincms/feincms/issues\n" -"POT-Creation-Date: 2013-10-25 11:12+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-20 14:59+0200\n" "PO-Revision-Date: 2013-10-25 09:15+0000\n" "Last-Translator: Matthias Kestenholz <mk@feinheit.ch>\n" -"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/feincms/language/zh_CN/)\n" +"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/feincms/" +"language/zh_CN/)\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: models.py:370 content/template/models.py:59 -msgid "template" -msgstr "模板" - -#: models.py:510 -msgid "ordering" -msgstr "排序" - -#: translations.py:259 module/blog/extensions/translations.py:17 -#: module/extensions/translations.py:123 -msgid "language" -msgstr "语言" - -#: admin/filterspecs.py:35 admin/filterspecs.py:70 +#: admin/filterspecs.py:47 admin/filterspecs.py:86 msgid "All" msgstr "全部" -#: admin/filterspecs.py:46 module/page/models.py:172 +#: admin/filterspecs.py:58 module/page/models.py:178 msgid "Parent" msgstr "父级" -#: admin/filterspecs.py:81 +#: admin/filterspecs.py:97 #: templates/admin/medialibrary/mediafile/change_list.html:14 msgid "Category" msgstr "分类" -#: admin/item_editor.py:159 +#: admin/item_editor.py:190 #, python-format msgid "Change %s" msgstr "修改 %s" -#: admin/tree_editor.py:234 content/rss/models.py:20 -#: content/section/models.py:34 module/blog/models.py:29 -#: module/medialibrary/models.py:40 module/page/models.py:170 -#: module/page/models.py:226 +#: admin/tree_editor.py:294 content/rss/models.py:23 +#: content/section/models.py:35 module/blog/models.py:35 +#: module/medialibrary/models.py:45 module/page/models.py:172 +#: module/page/models.py:240 msgid "title" msgstr "标题" -#: admin/tree_editor.py:407 +#: admin/tree_editor.py:353 admin/tree_editor.py:370 +#, fuzzy +#| msgid "You don't have the necessary permissions to edit this object" +msgid "You do not have permission to modify this object" +msgstr "你无权编辑该对象" + +#: admin/tree_editor.py:491 +msgid "No permission" +msgstr "" + +#: admin/tree_editor.py:509 #, python-format msgid "%s has been moved to a new position." msgstr "%s 已被移至新的位置" -#: admin/tree_editor.py:411 +#: admin/tree_editor.py:512 msgid "Did not understand moving instruction." msgstr "无法接受的移动指令" -#: admin/tree_editor.py:420 +#: admin/tree_editor.py:523 msgid "actions" msgstr "动作" -#: admin/tree_editor.py:432 -#, python-format -msgid "Successfully deleted %s items." -msgstr "" +#: admin/tree_editor.py:552 +#, fuzzy, python-format +#| msgid "Successfully added %(count)d media file to %(category)s." +#| msgid_plural "Successfully added %(count)d media files to %(category)s." +msgid "Successfully deleted %(count)d items." +msgstr "Successfully added %(count)d media files to %(category)s." -#: admin/tree_editor.py:440 +#: admin/tree_editor.py:565 #, python-format msgid "Delete selected %(verbose_name_plural)s" msgstr "" -#: content/application/models.py:218 +#: content/application/models.py:147 msgid "application content" msgstr "应用程序内容" -#: content/application/models.py:219 +#: content/application/models.py:148 msgid "application contents" msgstr "应用程序内容" -#: content/application/models.py:249 +#: content/application/models.py:179 msgid "application" msgstr "应用程序" -#: content/comments/models.py:24 +#: content/comments/models.py:32 msgid "enabled" msgstr "激活" -#: content/comments/models.py:24 +#: content/comments/models.py:33 msgid "New comments may be added" msgstr "新的评论" -#: content/comments/models.py:28 content/comments/models.py:29 +#: content/comments/models.py:37 content/comments/models.py:38 msgid "comments" msgstr "评论" -#: content/comments/models.py:49 +#: content/comments/models.py:60 msgid "public" msgstr "公开" -#: content/comments/models.py:49 +#: content/comments/models.py:61 msgid "not public" msgstr "不公开" -#: content/contactform/models.py:18 +#: content/contactform/models.py:20 msgid "name" msgstr "名称" -#: content/contactform/models.py:19 +#: content/contactform/models.py:21 msgid "email" msgstr "电子邮件" -#: content/contactform/models.py:20 +#: content/contactform/models.py:22 msgid "subject" msgstr "主题" -#: content/contactform/models.py:23 content/raw/models.py:14 +#: content/contactform/models.py:26 content/raw/models.py:16 msgid "content" msgstr "内容" -#: content/contactform/models.py:34 +#: content/contactform/models.py:37 msgid "contact form" msgstr "联系表单" -#: content/contactform/models.py:35 +#: content/contactform/models.py:38 msgid "contact forms" msgstr "联系表单" -#: content/file/models.py:20 content/file/models.py:25 -#: module/medialibrary/models.py:84 +#: content/file/models.py:23 content/file/models.py:28 +#: module/medialibrary/models.py:94 msgid "file" msgstr "文件" -#: content/file/models.py:26 +#: content/file/models.py:29 msgid "files" msgstr "文件" -#: content/image/models.py:45 content/image/models.py:54 +#: content/image/models.py:46 content/image/models.py:55 msgid "image" msgstr "图片" -#: content/image/models.py:48 +#: content/image/models.py:49 msgid "alternate text" msgstr "" -#: content/image/models.py:49 +#: content/image/models.py:50 msgid "Description of image" msgstr "" -#: content/image/models.py:50 module/medialibrary/models.py:231 +#: content/image/models.py:51 module/medialibrary/models.py:260 msgid "caption" msgstr "题目" -#: content/image/models.py:55 +#: content/image/models.py:56 msgid "images" msgstr "图片" -#: content/image/models.py:80 +#: content/image/models.py:82 msgid "position" msgstr "位置" -#: content/image/models.py:88 +#: content/image/models.py:90 msgid "format" msgstr "" -#: content/medialibrary/models.py:49 content/section/models.py:36 -#: module/medialibrary/fields.py:59 module/medialibrary/models.py:97 +#: content/medialibrary/models.py:51 content/section/models.py:38 +#: module/medialibrary/fields.py:66 module/medialibrary/models.py:112 msgid "media file" msgstr "多媒体文件" -#: content/medialibrary/models.py:50 module/medialibrary/models.py:98 +#: content/medialibrary/models.py:52 module/medialibrary/models.py:113 msgid "media files" msgstr "多媒体文件" -#: content/medialibrary/models.py:58 content/section/models.py:52 -#: content/table/models.py:82 +#: content/medialibrary/models.py:64 content/section/models.py:59 msgid "type" msgstr "类型" -#: content/raw/models.py:18 +#: content/raw/models.py:20 msgid "raw content" msgstr "raw content" -#: content/raw/models.py:19 +#: content/raw/models.py:21 msgid "raw contents" msgstr "raw contents" -#: content/richtext/models.py:22 +#: content/richtext/models.py:24 msgid "HTML Tidy" msgstr "HTML Tidy" -#: content/richtext/models.py:23 +#: content/richtext/models.py:25 msgid "Ignore the HTML validation warnings" msgstr "忽略HTML验证错误警告" -#: content/richtext/models.py:47 +#: content/richtext/models.py:55 #, python-format msgid "" "HTML validation produced %(count)d warnings. Please review the updated " "content below before continuing: %(messages)s" -msgstr "HTML验证产生 %(count)d 个警告。请在继续前查看下面更新的内容: %(messages)s" +msgstr "" +"HTML验证产生 %(count)d 个警告。请在继续前查看下面更新的内容: %(messages)s" -#: content/richtext/models.py:84 content/section/models.py:35 +#: content/richtext/models.py:99 content/section/models.py:36 msgid "text" msgstr "纯文本" -#: content/richtext/models.py:88 +#: content/richtext/models.py:103 msgid "rich text" msgstr "富文本" -#: content/richtext/models.py:89 +#: content/richtext/models.py:104 msgid "rich texts" msgstr "富文本" -#: content/rss/models.py:21 +#: content/rss/models.py:25 msgid "" "The rss field is updated several times a day. A change in the title will " "only be visible on the home page after the next feed update." msgstr "RSS字段一天内更新多次。标题改动将在feed更新后只在主页显示。" -#: content/rss/models.py:22 +#: content/rss/models.py:28 msgid "link" msgstr "链接" -#: content/rss/models.py:23 +#: content/rss/models.py:30 msgid "pre-rendered content" msgstr "预渲染的内容" -#: content/rss/models.py:24 +#: content/rss/models.py:32 msgid "last updated" msgstr "最后更新" -#: content/rss/models.py:25 +#: content/rss/models.py:33 msgid "max. items" msgstr "最大条目数" -#: content/rss/models.py:29 +#: content/rss/models.py:37 msgid "RSS feed" msgstr "RSS 提要" -#: content/rss/models.py:30 +#: content/rss/models.py:38 msgid "RSS feeds" msgstr "RSS 提要" -#: content/section/models.py:41 +#: content/section/models.py:43 msgid "section" msgstr "版块" -#: content/section/models.py:42 +#: content/section/models.py:44 msgid "sections" msgstr "版块" -#: content/table/models.py:63 -msgid "plain" -msgstr "无格式" - -#: content/table/models.py:64 -msgid "title row" -msgstr "标题行" - -#: content/table/models.py:66 -msgid "title row and column" -msgstr "标题行和列" - -#: content/table/models.py:72 -msgid "table" -msgstr "表格" - -#: content/table/models.py:73 -msgid "tables" -msgstr "表格" - -#: content/table/models.py:87 -msgid "data" -msgstr "数据" - -#: content/template/models.py:51 +#: content/template/models.py:53 msgid "template content" msgstr "模板内容" -#: content/template/models.py:52 +#: content/template/models.py:54 msgid "template contents" msgstr "模板内容" -#: content/video/models.py:31 +#: content/template/models.py:63 models.py:400 +msgid "template" +msgstr "模板" + +#: content/video/models.py:34 msgid "video link" msgstr "视频链接" -#: content/video/models.py:32 +#: content/video/models.py:36 msgid "" -"This should be a link to a youtube or vimeo video, i.e.: " -"http://www.youtube.com/watch?v=zmj1rpzDRZ0" -msgstr "请输入youtube或vimeo视频链接,比如:http://www.youtube.com/watch?v=zmj1rpzDRZ0" +"This should be a link to a youtube or vimeo video, i.e.: http://www.youtube." +"com/watch?v=zmj1rpzDRZ0" +msgstr "" +"请输入youtube或vimeo视频链接,比如:http://www.youtube.com/watch?" +"v=zmj1rpzDRZ0" -#: content/video/models.py:37 +#: content/video/models.py:41 msgid "video" msgstr "视频" -#: content/video/models.py:38 +#: content/video/models.py:42 msgid "videos" msgstr "视频" -#: contrib/tagging.py:117 +#: contrib/tagging.py:132 msgid "Tagging" msgstr "" -#: module/blog/models.py:28 +#: models.py:550 +msgid "ordering" +msgstr "排序" + +#: module/blog/extensions/tags.py:17 +msgid "tags" +msgstr "标签" + +#: module/blog/extensions/translations.py:25 +#: module/extensions/translations.py:140 translations.py:282 +msgid "language" +msgstr "语言" + +#: module/blog/extensions/translations.py:35 +#: module/extensions/translations.py:148 +msgid "translation of" +msgstr "翻译" + +#: module/blog/extensions/translations.py:39 +#: module/extensions/translations.py:152 +msgid "Leave this empty for entries in the primary language." +msgstr "在主要语言项中对这些条目留空。" + +#: module/blog/extensions/translations.py:67 +#: templates/admin/feincms/item_editor.html:33 +msgid "available translations" +msgstr "已有翻译" + +#: module/blog/models.py:33 msgid "published" msgstr "已发布" -#: module/blog/models.py:30 +#: module/blog/models.py:36 msgid "This is used for the generated navigation too." msgstr "也被用于产生导航条" -#: module/blog/models.py:33 +#: module/blog/models.py:40 msgid "published on" msgstr "发布于" -#: module/blog/models.py:34 -msgid "" -"Will be set automatically once you tick the `published` checkbox above." +#: module/blog/models.py:42 +msgid "Will be set automatically once you tick the `published` checkbox above." msgstr "一旦你将`发表`复选框以上打勾选中,日志将设置成自动发布。" -#: module/blog/models.py:39 +#: module/blog/models.py:48 msgid "entry" msgstr "条目" -#: module/blog/models.py:40 +#: module/blog/models.py:49 msgid "entries" msgstr "条目" -#: module/blog/extensions/tags.py:12 -msgid "tags" -msgstr "标签" - -#: module/blog/extensions/translations.py:20 -#: module/extensions/translations.py:126 -msgid "translation of" -msgstr "翻译" - -#: module/blog/extensions/translations.py:23 -#: module/extensions/translations.py:129 -msgid "Leave this empty for entries in the primary language." -msgstr "在主要语言项中对这些条目留空。" - -#: module/blog/extensions/translations.py:44 -#: templates/admin/feincms/item_editor.html:43 -msgid "available translations" -msgstr "已有翻译" - -#: module/extensions/changedate.py:32 +#: module/extensions/changedate.py:41 msgid "creation date" msgstr "创建日期" -#: module/extensions/changedate.py:33 +#: module/extensions/changedate.py:43 msgid "modification date" msgstr "修改日期" -#: module/extensions/ct_tracker.py:140 +#: module/extensions/ct_tracker.py:156 msgid "content types" msgstr "内容类型" -#: module/extensions/datepublisher.py:67 +#: module/extensions/datepublisher.py:86 msgid "publication date" msgstr "发布起始日期" -#: module/extensions/datepublisher.py:70 +#: module/extensions/datepublisher.py:90 msgid "publication end date" msgstr "发布结束日期" -#: module/extensions/datepublisher.py:72 +#: module/extensions/datepublisher.py:93 msgid "Leave empty if the entry should stay active forever." msgstr "如果条目要永久显示,请留空" -#: module/extensions/datepublisher.py:103 +#: module/extensions/datepublisher.py:128 msgid "visible from - to" msgstr "可查看日期" -#: module/extensions/datepublisher.py:113 +#: module/extensions/datepublisher.py:139 msgid "Date-based publishing" msgstr "发布基于日期控制" -#: module/extensions/featured.py:9 +#: module/extensions/featured.py:15 msgid "featured" msgstr "特性" -#: module/extensions/featured.py:14 +#: module/extensions/featured.py:21 msgid "Featured" msgstr "特性" -#: module/extensions/seo.py:9 +#: module/extensions/seo.py:16 msgid "meta keywords" msgstr "meta 关键词" -#: module/extensions/seo.py:10 -msgid "This will be prepended to the default keyword list." -msgstr "这将作为默认的关键字列表被添加。" +#: module/extensions/seo.py:18 +msgid "Keywords are ignored by most search engines." +msgstr "" -#: module/extensions/seo.py:11 +#: module/extensions/seo.py:20 msgid "meta description" msgstr "meta 描述" -#: module/extensions/seo.py:12 -msgid "This will be prepended to the default description." -msgstr "这将作为默认的描述被添加" +#: module/extensions/seo.py:22 +msgid "" +"This text is displayed on the search results page. It is however not used " +"for the SEO ranking. Text longer than 140 characters is truncated." +msgstr "" -#: module/extensions/seo.py:17 +#: module/extensions/seo.py:32 msgid "Search engine optimization" msgstr "搜索引擎优化" -#: module/extensions/translations.py:207 +#: module/extensions/translations.py:249 msgid "Edit translation" msgstr "编辑翻译" -#: module/extensions/translations.py:210 +#: module/extensions/translations.py:256 msgid "Create translation" msgstr "创建翻译" -#: module/extensions/translations.py:215 +#: module/extensions/translations.py:264 msgid "translations" msgstr "翻译" -#: module/medialibrary/forms.py:26 +#: module/medialibrary/forms.py:31 msgid "This would create a loop in the hierarchy" msgstr "" -#: module/medialibrary/forms.py:64 +#: module/medialibrary/forms.py:77 #, python-format msgid "" "Cannot overwrite with different file type (attempt to overwrite a " "%(old_ext)s with a %(new_ext)s)" msgstr "" -#: module/medialibrary/modeladmins.py:58 +#: module/medialibrary/modeladmins.py:63 #, python-format msgid "Successfully added %(count)d media file to %(category)s." msgid_plural "Successfully added %(count)d media files to %(category)s." msgstr[0] "Successfully added %(count)d media files to %(category)s." -#: module/medialibrary/modeladmins.py:77 +#: module/medialibrary/modeladmins.py:84 msgid "Add selected media files to category" msgstr "所选的媒体文件添加到类" -#: module/medialibrary/modeladmins.py:86 +#: module/medialibrary/modeladmins.py:94 #, python-format msgid "ZIP file exported as %s" msgstr "" -#: module/medialibrary/modeladmins.py:88 +#: module/medialibrary/modeladmins.py:96 #, python-format msgid "ZIP file export failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:93 +#: module/medialibrary/modeladmins.py:104 msgid "Export selected media files as zip file" msgstr "" -#: module/medialibrary/modeladmins.py:136 +#: module/medialibrary/modeladmins.py:157 #: templates/admin/feincms/page/page/item_editor.html:15 msgid "Preview" msgstr "预览" -#: module/medialibrary/modeladmins.py:141 module/medialibrary/models.py:88 +#: module/medialibrary/modeladmins.py:162 module/medialibrary/models.py:103 msgid "file size" msgstr "文件大小" -#: module/medialibrary/modeladmins.py:146 module/medialibrary/models.py:86 +#: module/medialibrary/modeladmins.py:167 module/medialibrary/models.py:100 msgid "created" msgstr "创建" -#: module/medialibrary/modeladmins.py:165 module/medialibrary/models.py:85 +#: module/medialibrary/modeladmins.py:187 module/medialibrary/models.py:97 msgid "file type" msgstr "文件类型" -#: module/medialibrary/modeladmins.py:186 +#: module/medialibrary/modeladmins.py:211 msgid "file info" msgstr "文件信息" -#: module/medialibrary/modeladmins.py:198 +#: module/medialibrary/modeladmins.py:224 #, python-format msgid "%d files imported" msgstr "导入 %d 个文件" -#: module/medialibrary/modeladmins.py:200 +#: module/medialibrary/modeladmins.py:226 #, python-format msgid "ZIP import failed: %s" msgstr "" -#: module/medialibrary/modeladmins.py:202 +#: module/medialibrary/modeladmins.py:228 msgid "No input file given" msgstr "没有选择文件" -#: module/medialibrary/models.py:43 +#: module/medialibrary/models.py:49 msgid "parent" msgstr "父" -#: module/medialibrary/models.py:45 module/page/models.py:171 +#: module/medialibrary/models.py:51 module/page/models.py:175 msgid "slug" msgstr "slug" -#: module/medialibrary/models.py:49 +#: module/medialibrary/models.py:55 msgid "category" msgstr "类别" -#: module/medialibrary/models.py:50 module/medialibrary/models.py:90 +#: module/medialibrary/models.py:56 module/medialibrary/models.py:106 msgid "categories" msgstr "类别" -#: module/medialibrary/models.py:87 +#: module/medialibrary/models.py:101 msgid "copyright" msgstr "版权" -#: module/medialibrary/models.py:202 +#: module/medialibrary/models.py:219 msgid "Image" msgstr "图片" -#: module/medialibrary/models.py:203 +#: module/medialibrary/models.py:221 msgid "Video" msgstr "视频" -#: module/medialibrary/models.py:204 +#: module/medialibrary/models.py:224 msgid "Audio" msgstr "音频" -#: module/medialibrary/models.py:205 +#: module/medialibrary/models.py:226 msgid "PDF document" msgstr "PDF文档" -#: module/medialibrary/models.py:206 +#: module/medialibrary/models.py:227 msgid "Flash" msgstr "Flash" -#: module/medialibrary/models.py:207 +#: module/medialibrary/models.py:228 msgid "Text" msgstr "纯文本" -#: module/medialibrary/models.py:208 +#: module/medialibrary/models.py:229 msgid "Rich Text" msgstr "富文本" -#: module/medialibrary/models.py:209 +#: module/medialibrary/models.py:230 msgid "Zip archive" msgstr "zip压缩包" -#: module/medialibrary/models.py:210 +#: module/medialibrary/models.py:231 msgid "Microsoft Word" msgstr "Microsoft Word" -#: module/medialibrary/models.py:211 +#: module/medialibrary/models.py:233 msgid "Microsoft Excel" msgstr "Microsoft Excel" -#: module/medialibrary/models.py:212 +#: module/medialibrary/models.py:235 msgid "Microsoft PowerPoint" msgstr "Microsoft PowerPoint" -#: module/medialibrary/models.py:213 +#: module/medialibrary/models.py:237 msgid "Binary" msgstr "二进制文件" -#: module/medialibrary/models.py:232 +#: module/medialibrary/models.py:261 msgid "description" msgstr "描述" -#: module/medialibrary/models.py:235 +#: module/medialibrary/models.py:264 msgid "media file translation" msgstr "媒体文件翻译" -#: module/medialibrary/models.py:236 +#: module/medialibrary/models.py:265 msgid "media file translations" msgstr "媒体文件翻译" -#: module/page/forms.py:172 +#: module/page/extensions/excerpt.py:18 +msgid "excerpt" +msgstr "摘抄" + +#: module/page/extensions/excerpt.py:21 +msgid "Add a brief excerpt summarizing the content of this page." +msgstr "添加一条简要形容页面内容" + +#: module/page/extensions/excerpt.py:25 +msgid "Excerpt" +msgstr "摘抄" + +#: module/page/extensions/navigation.py:86 +#: module/page/extensions/navigation.py:115 +msgid "navigation extension" +msgstr "导航扩展" + +#: module/page/extensions/navigation.py:119 +msgid "" +"Select the module providing subpages for this page if you need to customize " +"the navigation." +msgstr "如果您需要定制的导航,选择提供此页面的子页面模块。" + +#: module/page/extensions/navigation.py:134 +msgid "Navigation extension" +msgstr "导航扩展" + +#: module/page/extensions/navigationgroups.py:20 +msgid "Default" +msgstr "" + +#: module/page/extensions/navigationgroups.py:21 +msgid "Footer" +msgstr "" + +#: module/page/extensions/navigationgroups.py:28 +#, fuzzy +#| msgid "in navigation" +msgid "navigation group" +msgstr "导航中" + +#: module/page/extensions/relatedpages.py:21 +msgid "Select pages that should be listed as related content." +msgstr "选择页面作为相关页面在列表中显示" + +#: module/page/extensions/relatedpages.py:26 +msgid "Related pages" +msgstr "相关页面" + +#: module/page/extensions/sites.py:21 +msgid "Site" +msgstr "网站" + +#: module/page/extensions/symlinks.py:22 +msgid "symlinked page" +msgstr "链接页面" + +#: module/page/extensions/symlinks.py:23 +msgid "All content is inherited from this page if given." +msgstr "所有内容继承于给出的页面" + +#: module/page/extensions/titles.py:19 +msgid "content title" +msgstr "内容标题" + +#: module/page/extensions/titles.py:22 +msgid "The first line is the main title, the following lines are subtitles." +msgstr "正文第一行作为主标题,第二行作为副标题" + +#: module/page/extensions/titles.py:26 +msgid "page title" +msgstr "页面标题" + +#: module/page/extensions/titles.py:30 +#, fuzzy +#| msgid "Page title for browser window. Same as title by default." +msgid "" +"Page title for browser window. Same as title bydefault. Must not be longer " +"than 70 characters." +msgstr "浏览器窗口显示标题默认为页面标题" + +#: module/page/extensions/titles.py:60 +msgid "Titles" +msgstr "标题" + +#: module/page/forms.py:187 msgid "This URL is already taken by an active page." msgstr "此URL已被其他页面使用" -#: module/page/forms.py:190 +#: module/page/forms.py:206 msgid "This URL is already taken by another active page." msgstr "此URL已被另一个页面使用" -#: module/page/modeladmins.py:41 +#: module/page/forms.py:211 +msgid "This page does not allow attachment of child pages" +msgstr "" + +#: module/page/modeladmins.py:42 msgid "Other options" msgstr "其他选项" -#: module/page/modeladmins.py:90 module/page/models.py:174 +#: module/page/modeladmins.py:80 module/page/models.py:182 msgid "in navigation" msgstr "导航中" -#: module/page/modeladmins.py:105 +#: module/page/modeladmins.py:109 module/page/modeladmins.py:111 msgid "Add child page" msgstr "增加子页面" -#: module/page/modeladmins.py:107 +#: module/page/modeladmins.py:120 module/page/modeladmins.py:122 #: templates/admin/feincms/content_inline.html:9 msgid "View on site" msgstr "站内查看" -#: module/page/modeladmins.py:126 +#: module/page/modeladmins.py:142 #, python-format -msgid "Add %(language)s Translation of \"%(page)s\"" +msgid "Add %(language)s translation of \"%(page)s\"" msgstr "" -#: module/page/modeladmins.py:156 +#: module/page/modeladmins.py:177 msgid "" "The content from the original translation has been copied to the newly " "created page." msgstr "" -#: module/page/modeladmins.py:170 +#: module/page/modeladmins.py:197 msgid "You don't have the necessary permissions to edit this object" msgstr "你无权编辑该对象" -#: module/page/modeladmins.py:185 +#: module/page/modeladmins.py:223 msgid "inherited" msgstr "继承" -#: module/page/modeladmins.py:189 +#: module/page/modeladmins.py:229 msgid "extensions" msgstr "扩展" -#: module/page/modeladmins.py:193 module/page/models.py:206 +#: module/page/modeladmins.py:233 module/page/models.py:221 msgid "is active" msgstr "激活" -#: module/page/models.py:167 +#: module/page/models.py:169 msgid "active" msgstr "激活" -#: module/page/models.py:175 +#: module/page/models.py:173 +#, fuzzy +#| msgid "This is used for the generated navigation too." +msgid "This title is also used for navigation menu items." +msgstr "也被用于产生导航条" + +#: module/page/models.py:176 +msgid "This is used to build the URL for this page" +msgstr "" + +#: module/page/models.py:184 msgid "override URL" msgstr "URL覆盖" -#: module/page/models.py:176 +#: module/page/models.py:186 msgid "" "Override the target URL. Be sure to include slashes at the beginning and at " -"the end if it is a local URL. This affects both the navigation and subpages'" -" URLs." -msgstr "覆盖目标URL,如果它是一个本地的URL,一定要包括在开始和结束时的斜线。这会影响导航和子页面的URL" +"the end if it is a local URL. This affects both the navigation and subpages' " +"URLs." +msgstr "" +"覆盖目标URL,如果它是一个本地的URL,一定要包括在开始和结束时的斜线。这会影响" +"导航和子页面的URL" -#: module/page/models.py:177 +#: module/page/models.py:190 msgid "redirect to" msgstr "转向" -#: module/page/models.py:178 +#: module/page/models.py:193 msgid "Target URL for automatic redirects or the primary key of a page." msgstr "" -#: module/page/models.py:180 +#: module/page/models.py:196 msgid "Cached URL" msgstr "URL缓存" -#: module/page/models.py:395 +#: module/page/models.py:298 +#, python-format +msgid "" +"This %(page_class)s uses a singleton template, and " +"FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" +msgstr "" + +#: module/page/models.py:426 msgid "page" msgstr "页面" -#: module/page/models.py:396 +#: module/page/models.py:427 msgid "pages" msgstr "页面" -#: module/page/extensions/excerpt.py:9 -msgid "excerpt" -msgstr "摘抄" - -#: module/page/extensions/excerpt.py:10 -msgid "Add a brief excerpt summarizing the content of this page." -msgstr "添加一条简要形容页面内容" - -#: module/page/extensions/excerpt.py:12 -msgid "Excerpt" -msgstr "摘抄" - -#: module/page/extensions/navigation.py:82 -#: module/page/extensions/navigation.py:107 -msgid "navigation extension" -msgstr "导航扩展" - -#: module/page/extensions/navigation.py:110 -msgid "" -"Select the module providing subpages for this page if you need to customize " -"the navigation." -msgstr "如果您需要定制的导航,选择提供此页面的子页面模块。" - -#: module/page/extensions/navigation.py:125 -msgid "Navigation extension" -msgstr "导航扩展" - -#: module/page/extensions/relatedpages.py:14 -msgid "Select pages that should be listed as related content." -msgstr "选择页面作为相关页面在列表中显示" - -#: module/page/extensions/relatedpages.py:19 -msgid "Related pages" -msgstr "相关页面" - -#: module/page/extensions/sites.py:16 -msgid "Site" -msgstr "网站" - -#: module/page/extensions/symlinks.py:15 -msgid "symlinked page" -msgstr "链接页面" - -#: module/page/extensions/symlinks.py:16 -msgid "All content is inherited from this page if given." -msgstr "所有内容继承于给出的页面" - -#: module/page/extensions/titles.py:13 -msgid "content title" -msgstr "内容标题" - -#: module/page/extensions/titles.py:14 -msgid "The first line is the main title, the following lines are subtitles." -msgstr "正文第一行作为主标题,第二行作为副标题" - -#: module/page/extensions/titles.py:15 -msgid "page title" -msgstr "页面标题" - -#: module/page/extensions/titles.py:16 -msgid "Page title for browser window. Same as title by default." -msgstr "浏览器窗口显示标题默认为页面标题" - -#: module/page/extensions/titles.py:43 -msgid "Titles" -msgstr "标题" - -#: templates/admin/filter.html:3 -#, python-format -msgid " By %(filter_title)s " -msgstr "由 %(filter_title)s" - #: templates/admin/feincms/_messages_js.html:4 msgid "Really delete item?" msgstr "真的要删除?" @@ -770,9 +798,8 @@ msgstr "真的要修改模板么? <br />全部修改已被保存。" #: templates/admin/feincms/_messages_js.html:9 #, python-format msgid "" -"Really change template? <br />All changes are saved and content from " -"<strong>%%(source_regions)s</strong> is moved to " -"<strong>%%(target_region)s</strong>." +"Really change template? <br />All changes are saved and content from <strong>" +"%%(source_regions)s</strong> is moved to <strong>%%(target_region)s</strong>." msgstr "" #: templates/admin/feincms/_messages_js.html:12 @@ -813,16 +840,16 @@ msgstr "父站的内容已自动继承。添加新内容会覆盖。" msgid "Add new item" msgstr "新建" -#: templates/admin/feincms/content_inline.html:91 +#: templates/admin/feincms/content_inline.html:93 #, python-format msgid "Add another %(verbose_name)s" msgstr "添加另一个 %(verbose_name)s" -#: templates/admin/feincms/content_inline.html:94 +#: templates/admin/feincms/content_inline.html:96 msgid "Remove" msgstr "移除" -#: templates/admin/feincms/fe_editor.html:40 +#: templates/admin/feincms/fe_editor.html:30 msgid "Save" msgstr "保存" @@ -850,13 +877,21 @@ msgstr "下" msgid "remove" msgstr "移除" -#: templates/admin/feincms/recover_form.html:8 -#: templates/admin/feincms/revision_form.html:8 +#: templates/admin/feincms/page/page/item_editor.html:10 +msgid "Edit on site" +msgstr "站内编辑" + #: templates/admin/feincms/page/page/item_editor.html:23 #: templates/admin/feincms/page/page/tree_editor.html:7 +#: templates/admin/feincms/recover_form.html:8 +#: templates/admin/feincms/revision_form.html:8 msgid "Home" msgstr "首页" +#: templates/admin/feincms/page/page/item_editor.html:27 +msgid "Add" +msgstr "添加" + #: templates/admin/feincms/recover_form.html:11 #, python-format msgid "Recover deleted %(verbose_name)s" @@ -879,29 +914,26 @@ msgstr "Revert %(verbose_name)s" msgid "Press the save button below to revert to this version of the object." msgstr "按下面的“保存”按钮,恢复到这个版本的对象。" -#: templates/admin/feincms/tree_editor.html:32 +#: templates/admin/feincms/tree_editor.html:22 msgid "Shortcuts" msgstr "快捷方式" -#: templates/admin/feincms/tree_editor.html:34 +#: templates/admin/feincms/tree_editor.html:24 msgid "Collapse tree" msgstr "折叠树型" -#: templates/admin/feincms/tree_editor.html:35 +#: templates/admin/feincms/tree_editor.html:25 msgid "Expand tree" msgstr "展开树型" -#: templates/admin/feincms/tree_editor.html:38 +#: templates/admin/feincms/tree_editor.html:29 msgid "Filter" msgstr "过滤器" -#: templates/admin/feincms/page/page/item_editor.html:10 -msgid "Edit on site" -msgstr "站内编辑" - -#: templates/admin/feincms/page/page/item_editor.html:27 -msgid "Add" -msgstr "添加" +#: templates/admin/filter.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "由 %(filter_title)s" #: templates/admin/medialibrary/add_to_category.html:5 #: templates/admin/medialibrary/add_to_category.html:9 @@ -945,9 +977,14 @@ msgstr "%(comment_count)s 条评论" #, python-format msgid "" "\n" -" %(comment_username)s said on %(comment_submit_date)s<br />\n" +" %(comment_username)s said on %(comment_submit_date)s<br /" +">\n" +" " +msgstr "" +"\n" +" %(comment_username)s 在 %(comment_submit_date)s 说<br /" +">\n" " " -msgstr "\n %(comment_username)s 在 %(comment_submit_date)s 说<br />\n " #: templates/content/comments/default.html:28 msgid "No comments." @@ -964,3 +1001,27 @@ msgstr "提交" #: templates/content/contactform/thanks.html:3 msgid "Thanks!" msgstr "感谢" + +#~ msgid "plain" +#~ msgstr "无格式" + +#~ msgid "title row" +#~ msgstr "标题行" + +#~ msgid "title row and column" +#~ msgstr "标题行和列" + +#~ msgid "table" +#~ msgstr "表格" + +#~ msgid "tables" +#~ msgstr "表格" + +#~ msgid "data" +#~ msgstr "数据" + +#~ msgid "This will be prepended to the default keyword list." +#~ msgstr "这将作为默认的关键字列表被添加。" + +#~ msgid "This will be prepended to the default description." +#~ msgstr "这将作为默认的描述被添加" From 026d85cba0988084756bdb934c4e95246e3c10bb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 20 Jul 2014 15:57:06 +0200 Subject: [PATCH 1002/1590] Point users to the issue tracker if they experience problems with Django 1.7 / FeinCMS 1.10 --- docs/releases/1.10.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index 15df9431c..2c58d37d0 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -19,6 +19,12 @@ types. You should be using the ``class_name`` argument to is that the name clash test requires the app registry to be ready (which it isn't yet when creating content types). +.. note:: + + If for some reason FeinCMS 1.10 does not work with Django 1.7 for you, + please provide a description of the problems you're seeing in the + `issue tracker <https://github.com/feincms/feincms/issues>`_. + TinyMCE 4.1 as default rich text configuration ============================================== From 499b918eb96d2c40d3e4fcc70f9988b3248eeb23 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 20 Jul 2014 15:59:27 +0200 Subject: [PATCH 1003/1590] Remove a few unused imports --- feincms/module/page/extensions/navigationgroups.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/feincms/module/page/extensions/navigationgroups.py b/feincms/module/page/extensions/navigationgroups.py index f56e2513a..80c434487 100644 --- a/feincms/module/page/extensions/navigationgroups.py +++ b/feincms/module/page/extensions/navigationgroups.py @@ -6,12 +6,9 @@ from __future__ import absolute_import, unicode_literals from django.db import models -from django.utils import six from django.utils.translation import ugettext_lazy as _ from feincms import extensions -from feincms.utils import get_object -from feincms._internal import monkeypatch_method class Extension(extensions.Extension): From 913c38e57d0d58d671203fcc3edce077e76829d0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 20 Jul 2014 16:16:42 +0200 Subject: [PATCH 1004/1590] Fix a typo --- feincms/module/page/extensions/navigationgroups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/page/extensions/navigationgroups.py b/feincms/module/page/extensions/navigationgroups.py index 80c434487..fb07eb582 100644 --- a/feincms/module/page/extensions/navigationgroups.py +++ b/feincms/module/page/extensions/navigationgroups.py @@ -29,6 +29,6 @@ def handle_model(self): db_index=True)) def handle_modeladmin(self, modeladmin): - modeladmin.add_extension_options(['navigation_group']) + modeladmin.add_extension_options('navigation_group') modeladmin.extend_list('list_display', ['navigation_group']) modeladmin.extend_list('list_filter', ['navigation_group']) From 98cbc4b4159f4f3a12b3bb63ec796951327c19d7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 20 Jul 2014 15:57:45 +0200 Subject: [PATCH 1005/1590] FeinCMS v1.10.0 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index ebd94ddf5..ff3d19c0e 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 10, 0, 'pre') +VERSION = (1, 10, 0) __version__ = '.'.join(map(str, VERSION)) From f10f777cd9d06f375b2d12568ad627ea5c125240 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Sun, 20 Jul 2014 16:01:47 +0200 Subject: [PATCH 1006/1590] Start the 1.11 branch --- docs/index.rst | 1 + docs/releases/1.11.rst | 40 ++++++++++++++++++++++++++++++++++++++++ feincms/__init__.py | 2 +- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 docs/releases/1.11.rst diff --git a/docs/index.rst b/docs/index.rst index 18e2cbfee..bcd934174 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -78,6 +78,7 @@ Releases releases/1.8 releases/1.9 releases/1.10 + releases/1.11 Indices and tables diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst new file mode 100644 index 000000000..38e917c90 --- /dev/null +++ b/docs/releases/1.11.rst @@ -0,0 +1,40 @@ +===================================== +FeinCMS 1.11 release notes (upcoming) +===================================== + +Welcome to FeinCMS 1.11! + + +Major feature 1 +=============== + + +Backwards-incompatible changes +============================== + + +Removal of deprecated features +------------------------------ + + +New deprecations +================ + + +Notable features and improvements +================================= + +* Feature 1 + + +Bugfixes +======== + +* Bugfix 1 + + +Compatibility with Django and other apps +======================================== + +FeinCMS 1.11 requires Django 1.4 or better. The testsuite is successfully run +against Django 1.4, 1.5, 1.6 and the upcoming 1.7. diff --git a/feincms/__init__.py b/feincms/__init__.py index ff3d19c0e..1526d5fb0 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 10, 0) +VERSION = (1, 11, 0, 'pre') __version__ = '.'.join(map(str, VERSION)) From eac351b53b741c01b5a3f0515ac28b52e12df224 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@spinlock.ch> Date: Tue, 22 Jul 2014 13:42:47 +0200 Subject: [PATCH 1007/1590] Remove the example and the quickstart stuff Instead, people are encouraged to use FeinCMS-in-a-box. --- QUICKSTART.rst | 82 ------------ README.rst | 5 - docs/conf.py | 3 - docs/installation.rst | 7 +- example/README | 3 - example/__init__.py | 0 example/admin.py | 15 --- example/blog_urls.py | 15 --- example/example.db | Bin 105472 -> 0 bytes example/manage.py | 12 -- example/management/__init__.py | 0 example/management/commands/__init__.py | 0 .../management/commands/generate_big_tree.py | 41 ------ example/media/.gitignore | 1 - example/models.py | 122 ------------------ example/settings.py | 95 -------------- example/templates/404.html | 1 - example/templates/base.html | 118 ----------------- example/templates/blog/entry_detail.html | 11 -- example/templates/blog/entry_list.html | 5 - example/urls.py | 16 --- quickstart.sh | 20 --- setup.py | 2 +- 23 files changed, 4 insertions(+), 570 deletions(-) delete mode 100644 QUICKSTART.rst delete mode 100644 example/README delete mode 100644 example/__init__.py delete mode 100644 example/admin.py delete mode 100644 example/blog_urls.py delete mode 100644 example/example.db delete mode 100755 example/manage.py delete mode 100644 example/management/__init__.py delete mode 100644 example/management/commands/__init__.py delete mode 100644 example/management/commands/generate_big_tree.py delete mode 100644 example/media/.gitignore delete mode 100644 example/models.py delete mode 100644 example/settings.py delete mode 100644 example/templates/404.html delete mode 100644 example/templates/base.html delete mode 100644 example/templates/blog/entry_detail.html delete mode 100644 example/templates/blog/entry_list.html delete mode 100644 example/urls.py delete mode 100755 quickstart.sh diff --git a/QUICKSTART.rst b/QUICKSTART.rst deleted file mode 100644 index 6c89d9749..000000000 --- a/QUICKSTART.rst +++ /dev/null @@ -1,82 +0,0 @@ -======================================== -Setup FeinCMS in less than five minutes -======================================== - -Quickstart -=============== - -Clone FeinCMS from github (https://github.com/feincms/feincms) into your desired development directory: - -:: - - $ git clone git://github.com/feincms/feincms.git - -Now you find a directory named 'feincms' in your development directory. This is your project directory. Feel free to change its name: - -:: - - $ mv feincms/ myFeinCMSSite - -Now you can choose between the quickstart variant which takes about a minute (depending on your network connection) or the manual setup, which is as easy as the quickstart variant, but let's you understand what your doing. if you are doing this the first time choose the manual variant, as it's taking you only a minute longer. - - -Manual Setup Variant ---------------------- - -Create a directory named 'lib' in your development folder and clone the django-mptt module (https://github.com/django-mptt/django-mptt) into it - -:: - - $ mkdir lib - $ cd lib - $ git clone git://github.com/django-mptt/django-mptt.git - -Change into your project root and create a symbolic link to the downloaded mptt module - -:: - - $ cd ../myFeinCMSSite/ - $ ln -s ../lib/django-mptt/mptt/ mptt - -Step into the example app and start the runserver - -:: - - $ cd example - $ ./manage.py runserver - -The username and password for the examples admin-interface are 'admin' and 'password' - - -Quickstart Variant -------------------- - -Change into your project folder and run the setup script - -:: - - $ cd myFeinCMSSite - $ ./quickstart.sh - -Wait while django and mptt are being fetched and then follow the on-screen instructions to start the runserver and enjoy the installation - -:: - - $ cd example - $ ./manage.py runserver - -The username and password for the examples admin-interface are 'admin' and 'password' - -Further Steps -------------------- - -Feel free to delete all files you do not need for your installation: - -:: - -/docs/ -/MANIFEST.in -/quickstart.sh -/setup.py -/tests/ - diff --git a/README.rst b/README.rst index e3aa5b7e2..e35e7ecdc 100644 --- a/README.rst +++ b/README.rst @@ -91,11 +91,6 @@ Visit us on IRC! We are hanging around in ``#feincms`` on freenode. If you do not have an IRC client you can use the `freenode Web IRC client <http://webchat.freenode.net/>`_. -Quickstart ----------- - -You can find a short quickstart guide at QUICKSTART.rst - Optional Packages ----------------- diff --git a/docs/conf.py b/docs/conf.py index 26aa1b611..cf80e39bd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,9 +17,6 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.append(os.path.abspath('.')) -sys.path.append(os.path.abspath('..')) -os.environ['DJANGO_SETTINGS_MODULE'] = 'example.settings' # -- General configuration ----------------------------------------------------- diff --git a/docs/installation.rst b/docs/installation.rst index b2943fbc6..7c29615e1 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -18,22 +18,21 @@ are: feedparser_, Pillow_ and django-mptt_. $ pip install feincms -In order to install documentation, tests or an example project, install from -the Git_ repository instead:: +In order to install documentation and tests install from the Git_ repository +instead:: $ git clone git://github.com/feincms/feincms.git If you are looking to implement a blog, check out elephantblog_. You will also need a Javascript WYSIWYG editor of your choice (Not included). -TinyMCE_ works out of the box and is recommended. +TinyMCE_ and CKEditor_ work out of the box and are recommended. .. _Django: http://www.djangoproject.com/ .. _Git: http://git-scm.com/ .. _Subversion: http://subversion.tigris.org/ .. _django-mptt: http://github.com/django-mptt/django-mptt/ -.. _django-tagging: http://code.google.com/p/django-tagging/ .. _feedparser: http://www.feedparser.org/ .. _Pillow: https://pypi.python.org/pypi/Pillow/ .. _elephantblog: http://github.com/feincms/feincms-elephantblog diff --git a/example/README b/example/README deleted file mode 100644 index 4b33124e6..000000000 --- a/example/README +++ /dev/null @@ -1,3 +0,0 @@ -This is a really basic example how to use FeinCMS. - -Username/Password for the admin interface are admin and password. diff --git a/example/__init__.py b/example/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/example/admin.py b/example/admin.py deleted file mode 100644 index 5c92e55d8..000000000 --- a/example/admin.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.contrib import admin - -from feincms.admin import tree_editor - -from example.models import Category - - -class CategoryAdmin(tree_editor.TreeEditor): - list_display = ('name', 'slug') - list_filter = ('parent',) - prepopulated_fields = { - 'slug': ('name',), - } - -admin.site.register(Category, CategoryAdmin) diff --git a/example/blog_urls.py b/example/blog_urls.py deleted file mode 100644 index 9aae16176..000000000 --- a/example/blog_urls.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.conf.urls import patterns, url -from django.views import generic - -from feincms.module.blog.models import Entry - - -urlpatterns = patterns( - '', - url(r'^(?P<pk>\d+)/', generic.DetailView.as_view( - queryset=Entry.objects.all(), - ), name='blog_entry_detail'), - url(r'^$', generic.ListView.as_view( - queryset=Entry.objects.all(), - ), name='blog_entry_list'), -) diff --git a/example/example.db b/example/example.db deleted file mode 100644 index e1c34f7052126f9da1d4bfc0fc1fd8fbd8ed6d0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105472 zcmeHw33Oc9Rp5XBl~l6Ik}TVDd2M}3maS^3s{U4+ytORJYPl`RmSx#;5|r8`m0YEg zYw?zZL3Vc*PME_08A8Kw!g64MfpCUHNHUNB$(+LyGGR$3kT7I2H0c>~assDM4kv*y z_r3rAT2+$WOK4laTK)Y0d-vUY-+jw}%f0tqzH}j1$qGxwQXyFp6wbpT#62Sj9LFE# zIBpsK*MDhv!1@dPi!9F#9sx)2tNl%o+KGRKz%1eK;BVo7z+cB-!ym_A#ea>zi2oda z7XKmsH2x(1P5kQ`SOau!v?c+mx!FJ7jkw%eCVQuRGY>Vmn5<Tc^qoAdELO|e(xPNM zdN+1rufL}UZKNy7R6a`+mP^Izy7}Z8ogE*U8yDtA&R!T7dd-AhVW3rjUvDncE9BNH z+2w3Wn4XyvrmtMMAY7cCoEn*35S|-f7}CJjl7(!qa4T6#uOv$YaWP;5Uzwh~bY;9X zpm>`76Fr-jfO5x*K%blLw<E8Aa1cGXY?fg?TPozr<y>)%@@u~GbxLEVzP2JoEJb2v zP8UHgYn8>y-SzBZJvkY0nXFwtl30UHlaesdYr_h4|CaL*ES!Vj;s^x70SG2eL2xz( z!AS*zVG)8@5CU-kf@4P^m_Gu+AwL9NyCK-s0l^L*1T9UZZ({rp5OT|`Z|>v2&3}>q z2>)Yzo*&~6pqJ5ap%0(}8b<--<zC``m-_&>$`MX%zo!l~aRJmbnp_i-nT$}%E<>g4 zfX7AcF|fahi=aW0p2_C3FzDoq%L2%(bhkx|ScC}r9`GBW(1g~Ot)N<j0ou2(i3_8C zovMkF5Z3VtT}|8|>a&n8LznR~s^nSNYd|oH6oL^W&j<H3asB9sPKYKG8sy>F?j}w` z0W1D2ZIjJ93GMY*rvax^VQ@Mj?N!)ia6?2{W<Zpj_8jhL;!YsRLXkBUfi%D-MwZ2q zsBpWHfswXlVDv2+0&PYe5FTvMgb@qqv7JV-G{QmwxJ)i*J&X_bddz3QF&=a{MxMP2 zt+wLpK!mCevBQ916v=pp89DMSv=|VK7KLDh$n!z3twL!sAweE`o13_x)~XnOIs);G z0Db9&zQbS`1r3Igpf86#P26$Rtv4DCfDoZiL%4~Hp|GVA%>fEAQfAB$Z$LA8W*TBd z&6s1zkTuW~%mnDOr$-?eAmhaG13ZKXzXTzt;Fs{P;1A*#@GYFdv-lZ2i1%TR{~G^U z{<ryG<bQ;Jz~AH-`3roM7x)hJ9rQKy7w8k{Kck;O??F}ccJwR~(E;vXxtF-lbHC4h zn0t}C4<iNp`8_C%I#{tv$=j>}1+{oq05g7QuLs7P4k9cwa&Wf?^`mx%gpL(YYf&t} zHhgq=P&aBPS?T-00S{788_Sg|K+9yrk83F`vo+<|J`W0_HiE+%-A}pQSyPImT6|3@ z`e-S3+Dp;f=|O$S$B?W8J3U$q%T8j1b`Ls&d?X`z?e6lRLDb5!RI-Kje6o^#N{eOL z^w=X*BCRB=9(8z+2OUQ{bhhcxd`OGaS*CFZcX?0`vJBb>C<W*EykCoDS@luYPwBQ0 zx_Z<;S}yBA+oi>@tYq-qOH1k{*~sf2Dlx~vxm%0Wb7^B>Cq>mvGiour_Ir?o>WqFJ zS^~>&8M@kONty@_OKck@=NP?qYLN^F8;E?A2M@{5Vp?g8btu}Q#juQIcxj<U#v~Vc z^-{sv2A5_nishlBMH6k+Jjq1gJ+#TyjuTjmXIW{-haM<5XwPk=cY0VCb^mcC;7VXy zNuZUK*6sh>s?OcQx)RVOK)(M7&vWqS{#*&T5_nxCuyGu<asIZpFgzeMGLp;`a%(hr zCVM9di??hjT`a7pZe*6^#qvs0jzo`2vM7p2r{`l+#pGP#cJ<QTqjw{bTMJTYY+bpz zo+(_M5wAq<4vtr%a_r)*TQ_g!GGn*OcP_=m*{Sj=pd*Wt5|pH%ED2&_SQLj9C8S1` zSWE%biJ%w_N>M>nhUMt6EQVrAT#iS{_aEVJaq#E<TnV@m*cKAlf&GXMM=(rrToc#L zaow<YS47|C$r*zA+vZ0uaF8=3z$pwnvk9~YPVvqDOM{ypT$y{V?DWcvz)!+4+=KH? zUVnEtdbi~$k!)kp132=~T<7SG#6Rkx8_8ooD^n~-WrB7}#?IB2a;0)*u`x6Q%O@WO zDqBeA^5zL<EMlHuGCb?aa`|?#1m~gpF{dQQYoK!F#d0ONwA3r4ip9Kf3d(RmYBF8P z-GZ~y2Fc|rG#yQH^&n_rV5>E^)+=OSJGhc7WSvAv{NgH{3}=DY8lcty>Hp2#FLChq zW%Tp>Z}R_)KZW4+P4(LtYxTaGGw*S)*Wcfd?oXNL#cY?BwpD${woY?pNw22G);;|d zX2;Ks&yG)zj$dXc>#ReNGxY##5C+jo_D;p9$kxF9_7<;SQP6`?T8_*r9Ele7{c3vR zTqnwBFI63gM=hMabJaPv?oF<*FXoe}tflYN11rFIx;cn(0B&N0aahX-gYfu{X8(fH zXb`Sb)J3UI<WAD8{DA<vZ<8xKZDkqQTU%XevP46W?0xY@_O3ZFsMay7R#`&N1AQ~u zE7)qDHH++>^;{{tNIGxbE_}k*?4Jp2Aq}03E(rGCuJ8ZjU&7D7srtOjj4OfdBY}6K zMKrgP73k4#@7a72ioSw2rf4KR#D<8gXk*Zf5PGMxw}ljZ|1~9=Ug37KOjK{OpfOTS zr{PF+shZE<4G9ays!&MY6|$LJMS#ELax%9jz%X6B9csfL;`Skx!~Yw927e4r{ul5# z9>DGVH~GKje~14W{{5f@bdi_&HuV3{r{SFcDpFB&`&3N5lJ<alQg_#2DVJWM12(BN z@<Il0c8VMVwIroWg3nhzmrhnd6H3>hA;6Ys27dxHloI`s0#s2_Sjy$ILZy^kE5ji_ zWTmnBT&k2T-KEb2z><Cxl$Uz?yUomXGxUH0(~<roz)g0!$Ph84dR!mqG4*r>O+<uQ zgCb+~Feot{Ib`5r`&l}QgP^+P@9L*I6Qpfgl_#D8rKP^E9#H4dg+U-p?T$U5qvY@M z)8<Z6=)*zKL(&lvc5Dbi@yL#lR)wKk(g_MjU0q!yQvd%j=oSI@x?;pqHn)~8l=avB zpjUL@&;d<hjiqTXhd`gG+keF9ZFKdl^SB#SiMsq<M16t&Pl7|BLUicJA@-fs|6%_Q zfbLL#e;<=5)!AatL|3b9d4~3P;852g%e0j}c7pN{l#NUy$z+!Ny9YFcKz>v^fW*;< zBcKS>)74|HK}m}F)`~yD?c;ZIcolSUzmES0{~i8M`LE%h;eQ)n#b^2V@&$f^AH=Qv z&teq|{BHby{4V^idcDGpdom=j-_tdSXg{(KY5qf=E{P`84qyBFJ^c|>ci6FvQ(Xr= z{oVDU_8#!`AF(Cr1InHQo~|Gz>l}zcDd^A<<QRWCyF6X}$T{-t+T-c!p|R#@)6wqf z^3ymv&VVKmWF+ObjxcRBBbA0Rs_bm@bahck67Qp2IL49I-JU}SkZl0jvD@Q6qHVhA z!v?4U`MZ!YVtDs@jvPXck)rvqr@s$b1_bNiKo#o|>CkLY@KDzD@c`2j8Y2Nu%VO{T zFgTF?|L>5d`*!%}Cf8friqW%E8<$2TIW59}@g;Rhk<^HiT9V_DgrY<;iTF}V%1+On zU!9qlQfKC_DATLwSEsH{i8Esh%FNt?G&7dTEnJ<>PtPrH-10U}-G9fH=%!Xjr0I#- z{M5wxm8r2wae8&+-t_7UyiY3E$1?eutCRO2UY%N97O&4u-J2>*-CMYKb7W*qx-)Wl zWqv%LSjk+QEnZXR@3mgPc7AE0aBejz&sVQMJ3cypIe#NrI9I(c$Eyo+qMCX3{Q5#J zLNi<_oL^axEBRDm_TGgX(yi+g^W{rs-m%vCOVZN9wRtglE+M7m`McNT{EhUb*$X4r zu2fs$3`PoyYETvhNgWpDVMPu_W3r;E8@HNh!Bf$Ml8#4GN+hdFYEl)KQc)=tk1t7b zG?j@ao`8bO!*YCBPJ|L-G#X26^x!7afa0nMC4|x@QW;rIKyyl}nb?xN6ia3k@kIO~ z8_>P!t5@U&c|JcicRe>V$7+23%5#~C`Foj(>02qevJN#4wS4Kil2Xo>u3w$KGonn{ zD@PoTsKatBq^dD77TLJP)5=MwBvF;cbVgL;Nmb6qMM;#CDm=+csYpzD{3}O{4lB~I zD20gr?_yIc{tsL;|1TV#z+b|7{1M#C{|mgjKUV@zz66fqDO60ylWS5cq9!YOF;yyM z#rSeHeygy0ryP&2W)p1$sF0LkHXRr5B}z97@q4A^JLTnkPQ4LdzP)@qS`~c+XsZvT zmjG=w`jhW*e<7Zfa!X5<;#w@3QOnW%t(<bRx)hIQBB|7BJie1)+G?oc3D8z!E++eb zJpN;h{}%u8lV9O(30(<1u@dm}9xmX|7t_i7O0irSj*Fs178kM~)g*`{L4rTh|2<qM z80d1p%UAGk;Ekc3UVmR7y5DU*Y$D+Li3mJ))ISb^6yq$Uo(*IjThUAr&RXI8(l|z~ zwTA4qA3Rx&FIxi-q&BZV7)0;xva(BeXNVOF<JoxctjoBO{HWZM^V{OuA~|@ib2P)w zZ^+int3MQEOTSvfQtOE#E2b3|ief!mET&eo=?Z0oY*RAUSZpb~4u|u46@ao>%}F*Z z=u$qp+$)p|$$TE{fQ9N>IkyZa%f?wHL(6PW8lGpKZ1?&T3H1CPT4!WMs+qJbn)_1a z`mww1^;aM0QEQRzlRab&QCNp;O|BmjiJ8HU$vE~jID%786PRF!)6eHRn*EE3M(2I? zMPjw1wn`cHgrWcAuaiMBsoUoBCH^$ujD8mMfli_p?$g{lM{JC1f6}fU+z3J)J*Z97 zFa#w-MUbMyYIInNh2o%Kn24f1V5X|=ISUe+?a;EMEm>r;RE|W*Qdw3K5lKS6=&`j_ zdHsYI&SlFL?PNrTGmf<ioN~YkM~dve2$f<Hoo&}}j@H2`Dj^9_MkB}<vEm$AD^^y( zOqAh4a+`*uuLg%YtO8%Lgeu9%r&3-n63Pmab~=h54JxqgkCJ6SDZZkpQ5kj0M)74N z`8LU-hGNk~EDl+$5=*tVQXy|3oi&Y2WH=HVRuZAO6pJcR)Gp1f<jMm4C55%@?Xq?# z6bgle)hdV&96Z2TMY)n&TNa?;!cujOj$KJ`9&i^$cW7)4nj~aU6^#r_@^B;?O2i_n ztRSB<mAsqEn$kydi$iMBppj3Gg9H+hNCNp}OAR8~+bEATtcszCB&&*ue3F?*LSxNZ zo(YpbqRI*zEQw)R4T(xTBCEikUaPce41|+fB?rlCIDq0!8kVpfivoJG!)h!fsj?i8 z1GlqT7~k#+1K|>VfSjj2TFw)7aw<|N9*aq06nMT|EMzMyM8*T*vi=PDRjlO)wP3p{ zE-b}mIi!eDSyWN0bT(Pe3Ukc56NPv!*P%MOB#@LW#p4OIL%y8LWK+o!l92{)v|(N0 zmn`^|5Yg=WzF`Qigdv#if#A|E{rn$Z+@C7}R|4Bi0<QhvHmh*AxUK{&5^%r&7Gb!L zt^~H31W5nK=&c-jD}S5+DERxi!S&aOU}N`Qum8D0v~hxZn4?<^mTd{^wiE18IFb*r zEt|>dvGHr5{C<D`F1lm)z+pb3Z2@WfK6J~BZi1Be*4go~BtPn2&uiO^GxlX_-QZcb z<Jca|_9-d&5p1xNrOO*OvJBzD9@d%8X8+~jrh8bHO13yMWUXZ1{qfyi|Hue>UfcJj z5~n$6U^Y%mdvd1u8?`Ja;P<wTnY_PVyNR?snkkzdIaGu@|F0SC+z3|!+eQNJ{D0e2 zwOdeE0yPqFzyCENaU)y_Y#RxX{(qLQaQNH!75okSGWg{GGX4Vo9R4HxU-5szzkol4 zU&KF#|2=*$zK`Dt_JQkQDU`wAhp&N$;0yR1cnKZ`%b*b04EEx~uz#=%w_*?fUH+f= zf8@W;{~iAo{;&AI01v`{!2dpY5&j7O>-;bCKhOU(|3UC4{C@u3{15Q=K=0_&_!Ib} ze2V<HZA8CK3W`6<?e>pDxYIudVY7d<2_v-cEDc9!_zVfV&d~5Q4NsA9?@1b-py4nH z_atZ-r(ukQyQ4IW&`>2|r$R%Sh7t*Pi8Kt;Fhs(RAPt9TI7q_wr)e0V;Q$HSj??fM z4f{#B^C%7bXxK|aUk?oh8g`Sg^(h)2q2XZ??l?rlgETxq!j}Cs^wV%33B6r3+)Kkf zBy8SI!%iCRB4JYp4clqhMneBM4aaCmrHXfuXWT+VFA4c(8aC0;LqddU$kPz%-+$8o zw@HI^i|I;WyGvjvB98x?VU&Y^n$Qn%=!ei(;RN7onBMrqr-_57_jOSHOrkwSozNQ( zPuX`)jrd31DBaBcQ6*Q&gHo-olv>Y^OgUc#ZB!k?su#@kP}h?su<f*Nqq2nD8n}wO zm0PCf_4VB^6>nurB~Ywdtd=akYU=66mcVGgM3ieQMU$I)fQ#v5dL;`!-y31Pyr<c} zJhJt!xO0Qrx<Bqr+yA;A-Vjw?%O0}h<fm7dnT8V{I}kY-aKZ)Fy1f2KKicRp50sd; zuy%71J4Iq~2OUR9gn$FwLfTL}9_ZC~z60OC&+9)GL>t|do>MDar|FD8Y^Uo?*0X7} zovEbU2K|kFey@KD7&ud(0f&H`xQ=YWh$DMrhMa(O|NjL4)Ai>6bWZ-pt^&6EFzl9p za|zHnDxLo$I{!y>{tt@0WFAZB|A@~25uN`dI{!y>{*UPVAJO?gqVs=5=l_V#{}G-4 zBRc;_bpDU%{2$TzKce%0MCbpA&i@ge|06p8M|A#===>ki`9Grbe?;g1h|d2Jo&O^` z|3`HGkLdg#(fL23^M6F=|A@~25uN`dI{!y>{*UPVAJO?gqVs=5=l_V#{}G-4qn%U^ zJ{q>tkk0=Ro&O^`|3`HGkLdg#HJJa?{y&U&nJe~&y8&d)|BP+Dudnv)YkXMY!<zma zS=HCsIbeGV{4Z}_`)=xXmjG$gKHC3%wEyp={ohCXzmN8RAMO7>+W&pD|NChF_tF0E zrTyPa`@fg=e=qI-UfTbCwEz2P|M$`U@1y<SOZ&f%_J1Gk|32FPeYF4kX#e-o{_nM{ z|J!N*_tF0Eqy4{=_Ww@W|2t{_@1*^|llK2k+W$Lg|L>&zzmxX=J+%Mtq5Xdk?f-jd z|M$`U@1y<SNBe&#?f>B92&B|b`@fI&e;@7tKHC3%wEz2P|M$`U-%8j2JLvj<2c7@7 za<6dcy>S0#6|1mgx5z(*{yQ3j$S3gklc>)>?d#-F5InQDwMF1Ng1X?&)63NqG3o(7 zU6;X%QINqd2;PIl?lCC0qHw8Ltb}cmVIF%?3Jf;*v#o$nI>Mm?Z3lFG&w}*_Sr?fY zS6B?grC~%KFGq2lKm<o0hdSCi8sY$h&2oiWvjim+4#UEYW=2<AAafTKqm41JjL=!I zek5*iP?&^a1iqmNA>I8v^`%)35vXyvf-#pZPa6xO@jGypCAm@)o$&(VKH#dYjX1KW zlA?Aw7fI1nlN}X>EiXXLqj9$3X$B0>O%Pe9Z5XI<>e_Reh~ywO_X;v2tsoeC@m4~z zg=igEV1uVMgf27z7jSbZa1qwI&~1ena@|&ly&_~-53!gq_8<-08P8@?QB3|7E3*o) zgEgr<iwQfl0Rm5&SRJNS;IA(Q%}=v(17>XRfJtYCZ@`KsUXvBs%8DH3Ft4%FhL^zp zZx;uazdr(d_otu0F7Fn}mB2$wU<fyJQ>Y7_T#--fBSfVL7k1pr=6iam73#?_r18XT zojc}f=0*UTm|5P=RaOLI^rt&F93sZ4n8E@1p~(hVojAMsW-f>hA!gNgyeuq(9bzQ} zj>4#!ANL&G!n?79VIvlYIzh@<TWeeE$@SAC!pU-_R9ss=oyt{ChS{@FD3-Fo?8)%@ zX>e)+B_R8MJU7O1W8m-eGx!+(;fEHL0r<kc{nR1+``+R17k*Fo3oo$k%=}WtyqLR@ zQGRK8<sqOdrL6t_>PF~jkJy^3?pf3B6I-@;7-$_5%)Qt}@J*o2J&b)_vXeR_kck*< z<eGZd<mz#&&NbUIBXDHrjhM;@?h6NCn=yizsyX>4(v57(jk5LPy4h|Uy9m7=$fNFb z6Q2w9y?fX0Q5)VAY~?e!&`ZbaUUN@s-FU8X-T?O$fPdOG*eiEl-mdxockll*hBEiT zmB6-=06G6}#TPmJ%eaVB__O#T{wDqk?Ad(+-`Q4za0}~7;B}BdCq9l~)o$(``F7$X zNZ<QuZNXjC<#0;}?nCD4T=n+g3Cnw(&5Y(fcn~=@DVpq96c3?p+bO_y2${FPOH}`- z75@<j8h_uye~<qPe;&L5eG|Wg{{|x6pDO`Z0*{FV$SFXp&x2tzn*=Q+php0j3Lt7C z5$ptzJn|%HZN=Y)@4t#bpZ7zc|N94c3QqUF3|hV)!Qc0o6x?OgmB9B@0{d~K?tzf6 z6(3*;a2nTv!iap2EoT&J*c--aYs^+B7|mTcTzeAH<iM+hJ!E#^I3&OhC^^hi2I+ZF zOA<uZ9A@ADPjjH}uj&75+W+5%)BCS}Plf6db0y$P;8jV0eEE5*1;8QlT&w?sYxI9O zP5-}@?Eib=+7I~q1JsM&js6dR4<FzP+)++o%y>2q_kr?aLRVfib|M$8H>JSFDpR(t zpB{uwRY2&u@>H|`csCqotYzS0Lt{r4wy=$te!I4#5x+?HxrvIY5k)pbNo?R+ce6jx zjcz;8l1*;|IM4{Mwl!XZm_`Rug4ZAJMjP0Hn(dSu*q?5M-PlsEA)u!O-qO?TAM8f& zaFC#T>;{3sMg-Vad<}XnKCrR3*Xy5*ppBRVy?GZ-y~;CFhZ+$!K}-ai?y14FWviXk zmC;Cg1Fu`F8krjxm~$DEZ2hL`WX=lZWG{2n>+k774>Tvm<fFMrFA6fBLQF2~oWM)~ zRILL1$SFk4o_if9*z46)K34|S@cOFguZt?YPGYfWxh)v>|M@X)A9tR^UxXdNcY<Bt zFy6<1oBtwM>K#BYqu)XwKm|080&wQ|68F2@2e?%L*8XF|gZ|G`2b#D5>KRS0kxK{# z?Ob99JT7XFf&EQf1PzjOxc)T@N;V);%}Z^I7C{_#QxON?f;|SRxstYkGT+iVXdhg( z7e@U$RTCv4tOE&fyWSw`vydjoL|#UfJPUAz9)n;MDFh=%o)3bn<bHHSCq$D84f1dd z?#+`>z=|JkUjzl3W}SrgdJL}4V{keZ2B#C!UIn;Bk8wjp$*zQIrsOn;FkGc~0)d-g zLzqmno8BeY#K^KZa;IDv?$%=&7-?GuM&FVl0Qc^(Iv_mQpa~-uP-p=qd-0hHzK8L_ zUIFgBz4$sDBX7d>T8gg&5vuH2fP4Dv6-qSiF(XHw1-P%zUZE6%5hBkAy|xOa$%F)X z=!MJsf?BK6aKafp_&DMj0s7Jlcla?FCQ%KBk)SV!Jx$zk)U7uf4S*1#PeX8pUkrsU zm1vq)AV$iJ83GM12F>W1X^0UuV~)YiUQE_NPcReU3bKsFgoAwl{aguZkozF_3GS<C zCyJt3R6+j{eG+|xKf<4d8vs8DqrqSC-^IuAJbnSjiO+M>dat+t+bbC|AyoA{+&T$O z{pILE(qoU4QnPZfp@Nk`dpml_fMPYkpqN~=x8B1xdir5=E1{>q3><;0IJI$y(bH2} z8Abhl;3)%=(bQ8~8CCuLV7IO9kk5{f$`u|2!P)X?GNVPFg&qTf(V-BG26;Z-OE{qe z3XvmxXY~%alaMjLyTLxVH&kmvtZ-IXM$-a*)BtCct>BCS6TGjVG~b}!eCgM+jWA&S zZU&B#I#4Y2slhSgHqhe+C?l_dGQw8S!vnUSLq7}cgfxBX4H)&#imd@Kni|a01`H#n z!7yU<<@jJDId?eZJY)!t5wr-dgON1_7YrKUjJ6e=abSY?g=*!zt47XYLwJk@Dz9CP zxK(%o(Ew%SHBd&_3aXv|!TO)r{%dRhSIF8QECAg7fBWF(zPS>3Q%ZoW`7vGpH_`P! zPxb$K%jUm_uK#(u`_EJTe@xf^9=KbAod47Pzi&XVe+9;Xm#O~`*a3V~7S?6Tm4GV& zn*>Pz_tO3kUP9oxiS~bwrT=U8f0&*A5g4BKf3LOwzhd-!G7@~*?f*6*yDzQ;-lP&B z{TW&I|2f+KIokiN_P?B^|7-jI9PR%e{IX&H|0XS>%a$tvR|2m=0%VNPzW>_%AM8QN zsA2g3dJU-EtgZxH2|T6}p!R?G0*9Z6!2P)ra3%1nB@hM6T@(l?XgYgaAld-h={DTP z8YFK)dgLIBk{A@Fpco-H#Yz&~;(8Ab*U<*Ls-RbYg)6!8RU;52_q_&*Z2_441#S1d z>UWQlTWZ<$v84YaUgqG>{kal&2njqO_UG>*_U9MCn7kn5*2~p`kSXTjhG9^K5Rz~O z?hrYyEQ3$PY^7QPb&%Y8uAEDgdvUXH-!NG7!kyunqL9s1%ixFvE+#IlL+;#KI+w|1 zs^n(zijYsH0Kbr}Xt=XNA-TMk6yU<*o7H4UxKe@Ml`8;pp^zgFx8OBd7!qz);SS`r zB3QgvGeY)Gwv^6QsGmonn$IT->7s_200C2k5=EI?2Vfza1kMY<Q&B4ckg9})F@h4@ z8fJxDsR}%4h0U#jlFNE2yOIS}wi1*aB5oD))pa131$LmM0%&W1d44XR*F^*cs>0>V z%eiDlSR)L9`F{yss-=)HekYw>uVg`DpdD8cis^JR3#aBny1EYj5CJO`YfV@$6~Pg} z8j&KA6c9~U^Xo}cZlSoe1Y%Btf(<A!kkmpEZfb`T5&?nrG`UEd%C%YunfCu4PUQH% z<V5}*=qp<_fCs^2UjK;`=!Kiq*5A~5vYiPxh?W{DOxZF&s`eB;&NL06>v;+_)y`_w zv8+bqCf`IGjM$LB9#+;2$9fUE2Pg$uSv767!3;i`2OpwfC~lg*M<M~JbFHO7r7k6_ z`HFD-ICQV%IzhE1WME_e09@S`)30tb3usXyFqQY}CP(b*e|2F@6q<@%T_A^s-CK`? z(qj)(dbDI9Ze7h+wIOxQ{VUOWG@%Iz8XvfSwBPHG#n6LgXG1m5-OYR!X@na#QZwVD zHqqB^{%^ASdbUj0{(r0S&P{hE@FYv175y)+2Z<aKLCg1TsES@dA4I=`K8`-aALK=T zl27p!{(W#?$FK6A<o}faTmIYNC9DTW@FadKE`gtbAIHCh{~K5jzpVX-4sid<y~KT< z`+e@i+>6|O&=+PuzXuGWI%;&Ef?9ly3f0hF4`>}b)UXD3dr&`WXGrLJ>S-;C<)=}B z4iD-^rncC?0S{78TOIAE<624`6{=(VJSd22l->F%R}LLYM2k?XgUM_0jIODIi79_P zQShRApdMNTo^e5=nzSgEl}0tUd(aVtNiL$I>h1KPK7?5&64Ro^uskGY2Z;V8@{lY{ zah9libRiGR#Ug!LB+JMmcXoNuAZj9cEvmk4`#nfPO)S49p<PR0I4lVrlq;+5@-8aF zW`=_)H+O20EI*6fO^fU$JP<YOJrtE!&j>MlwHQ4Y#B@=?wU8{j_V+$ok`|UtkM(P@ zEUO;7f0qaKAdA-efju5{9PMD4HLcTwS{%!&#T}w_ZHlLdDFvsJ=@BiKW!4o+pQ0r- zbV$2txqOT&)fv@dST+*VLnY?W2koUzZl}&}@;0l9J}q8n*@!<%8ic@oi9<6ehaR9G zMZbVPhCYk_4t<yJ;=|DY-^!Qx_wql-{~rH0{6FFr{1ld<@4p@YJNz^FQ}`>;r@Od+ z;=Y8QM*E=Wzs&t1_lw*M+zOzz{SJFj0_`K!l3ZWU=U`a_(^tmaGd&(Oin<tc1#qXI zT*`rkKq<La&QriM8U!m=J&4m!dC)1;MF{B0l%!uTaxT3>W?_uvxR$8P$(}eyM+HB@ zRkEjyc6-nnw2$GeEy>x&<4NN&$T?ckmekHz(*`sxijmcZJzD$D;gQyItvc$E7O#uK zsQn-v<Z3icLzLHgilt#Kg(0%)k&2W>o1(WwTY4ueh_3!EYq1Q49;+Pmpa|M+t-dU) zD)op5oj|*tb<a{GS}H@QSG}G$O1auY(CU<8l>QzES8*-Y!Bv8G^u0E&hN;Z<I@vj) zMLYR8S=%hF?fTT#?Rx9Jv1!-R8Z6_sw!w~&{?Fr2anP5)VC%5%iz@+F0*`|PcH;oD zpE2+Oe3e9PeIh{5{}K2Afj{@>O2C!Cwvm9V|FdnX+AXLnfd&$2<3Gz`Sh91!h|cp5 z@cZ!lxSz9uZp4SY{$LQ@@1y4^?EVO2IpusmVLv@_CO_)I$r_v{13R7#A>j4ToIo3+ z)Q5$68e%&+G*6)#07M%eCRx|ACYqYVEGrl}h%pZq1NWm((*vjHea-_Xw)BKMHY{wJ zk#W1o>cTv#+~^*G_2R?&PNhv+j#DLlwY)WoIyG!LIK47GdFjeH2+Ck+Na(d953~j* z2b=wGi#59S&}30>b0Eh>scv)vbXnwo+s0}h?pl4EvlHOP7gn|gpq1Z_!3BYPXajdj zb&+IsMxL~{W@j?ZqqSgX5~*$Nn3U@O;D6%a&;7X)a3!!!B+!gJ;3!nn|3_~B-zK&0 z7Sol0CIK&8W=4K({7=IDKkwnV_n;C2H$eYJzm1hJojl(!(#bPD$I0hXrDW-@KJB|( zH}Z^q@?00@Q76w1e{1!w@;2xFx<Vo7?~xgmp^+z9?<2S9?gj226TSXKLRU<)aZF#x z*=POOXErIUk@ZnaOURkC)_U5L#DACtLN=8a*}OJQE~p~j>p)92TgkzVRMRta!Zcjb zqXQJz@0N1(0wVpocAHc|c!Ui&<-Z3ywriE_a<&9BVwCldjG*UdXqzBs-mo%*z$hv^ z18kgf$}X_RfR8G)+WI$&{Kntf!-Q&xq3$A$0d1jl8fe2G=UVs=bNH|M4}&hxI-KqI z^55bA;@@Z-aLIn}C4f3m8%py)nEda7|3~5fvLAwXBCf)56<C||+&ek$0pd<(IPUTQ zg0$%Y3}J=9PfbpZ&ysDU*~5@BK+w$6#1?oez<5ALkO6q+XiyHpQ}}{5yoWE|t*jK+ z!g44QCQ3eVy=nRe^zw4};^c+!Bq;r7L+f`dWSt6{HhugKuD^%QTt{K7SuU3D3U}__ z({~htGHT|z{uTi0qn|eeNDfIRki>hMc+~H$2PT_fGS6cGYpw-TEZ7tY^BBVo;k96r z1x%9Q`cH)VJ@vp$qLK_g`Vs2EJGdT4ITeF5g?RXfU!N1i#6txEnoKoVOfg8P8PWUy zF!wQz`xt*5|0ja<G5OuUA;FH|40?XNcE(_gj20Cl8mCVw>H&<{zZF};zfqrz`h<a+ zWm~N`pIlq6l5b(Un6ZAFE%)l_pI*&U!2EtYKfGWok}l;ma{_98P{-gPaK9{T(!R2Z zwDp-9Y|zy&gau&qVWe$=e^hB3HC*@OX!}Oj=hY!_z3)9DIz5{mo3Sfu<Fa;VG^sTE zt22#uM(gu!k=dfOCCC^VS9$zr9R9x$xIb3{t^^))33TybO$^qVhY+>!1E0mzY^;kI z8Jp4IUzkRd{=bL22va@oL);&6ufQDu^XLcBuc0sUJRjia`3L;(fy2N_d>{WF0o&p? z_w*?7+e^K{g4(1&^k>1m^G>CnHtoZB3m%XSpS+q9qv=%Gp~5+!7?7G4rU~g#>l{*v zZ{&#X)|L*Ebp2UZ|5T0;zsn~q{%tK8oNAzKMJh*)Jd77h9;c2d%hMY({M8c4>0b_; z^6Eg`D5FCfPKDNigaPT0#vX?>`iF@$s6S>x*JRYL_d0lj6p8u*W~42UPB9FgG=OW$ zzt>s*lc$=vNpz~VIt0t~&8FFHRiQn5x`~@XqjjsthQP_A1^L-C296qbZ8)5)TX4jl zY2rpvLNA3y)mC@i+(7&N)Cej58A}1`<z?Jkl324jb=Jtvc(=e9q#5IuB$l1@e-Hj0 zj^6tDIe2h?t^`~OJRTD0^myP-icx(d1hyMcJN9rroDrq8^R{=n9nSqM=@RMx2!E7= zKlkTKz?HybB7t)-ouBZJv|&06WBXcRa4w{TB`HjHg+i<A%T!&BL<S`(D8&R(9Tvgk zkQ$OBu|!mATK*X6|8&pyF)6pprYiwg0<WJ0NdM>g7die#u<3{YHp9Fzq<Z~VM$pEL z<03ga29X0?wx}=_Xd9onj<XHmnw#4iBXi!~=7c1htmeV&Yu~eOaKr#2`tV~U24MH2 z{<lD_y=ALfGvo=I+>I;l+(TEK72m_uoeds57e%d}i)f;Lexq-Wm<_FN^0RhU>%y2Q zG#2XuIa=1nvoWtfJ%cuGP?6fQ&==AdEPDecjV(bZH(_~m)OFaem%&jK_xr!ui07uc z5_qyDK<xkB`Tvt$$8PCd2{e*`=KtdrdjCfw7&qRPfGdF~M*`IH-*W#4kB$ESmM5o_ zZb@7TxDu!*0c-y!>;Gn=mOX%eoNwnpfOp^@sF&w{K2F^Lyr5aPI}M7R?{9z`0ILRT zjRi_$%WB;YB3S|xbgT9zOUN%(dUcZ%p}JPiEw6!ddWZc=iJGo3!<2?ll~OiqrO*&C zp9Symn^0{HR1;th^=Q`M=j}U3&Kh|rYw!)vu-88VbdT4!LN|6-o!Fn-g1C`U+of`5 zcWg?PPI&zh;G&~G7f@wR1Q)iTPivXD3U_8Clu2TsdU8{VlNR92JGBK-t<^N5N>c;h zf6D7W1x4+yUsTqloRp`xplr0nM#Oc10Ga=L@ZWRzJNR4pAK=0Lxe{<C@FYrre)c_J zIRqC0Lco*2z5nk?tZBDQt^^)Z0_6MOf*)}3?f(t@DY*Ch0sc|^=a?9Cx<6L}t_0qA z33T8-q$@N8WvRvfE_-e7iqvd-m!u~9yX<MlJtjT{+g@ef_A1fue+&L|WB!j{!hZ?< z|8L&-V!ISv3Ahq?10+D^`Fslvy(GlVbmreg!+P`o7W_GS{)fK--~TV;FThPcpL+xN za#6Yxa3$~tOMrB8kEQeTwDa?{^LspW2mo_l@Qq?Q|D*k1>-paxeII`t4g}qwD*;ym zkDUZa-)^G)A6q{DnD+lB+W$SY|2NbA-^}L!^!xuZeEna6um9&@9`NPIuHY`it^`~O zaHRh?p8S(kO#46Y{Qko?ANoBR1IP-%o&URS$(6ukC;>XRr{8}>zyHX#_$R3x?f)F@ z{~RLvKOXK92Y-LehxnJcpMd{f%kR!<@NNqV4gUHH4OI2Tsm?I7g*pS%muaNTpd|<H zzx|BYKR%A0A9eVPt@V0hTDR4vU1rS8jhwwOE`ULy?sm2o6qH9=1^5xqe1;B@t~w-K zoSmE+nOzW`8(%P$kl;R(O14z)rB0E|Xoqf+p?_p^RA;b4lvaRbfaTY2pta~nMIto{ zQpHjxTgt61*Ye4bR7-iV-dqAxwaSW#%H|HZHL#&R<Ml6$qm8Syb`6H=T<U7tyln<G zXRrCqKuv^BTf({(W3vR^KjQVDIDsBa(3YV$ze=`TDS)MXp5888ZV-Ld-X0o2J!(@h zY1eBztWJnORGUJX(Y9vC&yCNHPmhjY7J4(Q;0&@z%V2L9hMPefF>o`e<AuvtNdMo( zo#OCk@K50-e2o7({|j*A?`ggn{VXb?lc<IJG`9`_^?uT>9oz^)9X+TGyh<j5<WCW# z=&%|cmSUlJT#hHAXpdyLBazT-hn6L6$s!AqIvj}%D{@Fy5)tr}>Wdy*OO@A8XyF{x zlR%n=APcvXYn8H)6w1{Ujj0ri=xn=&bF>al5nQzb%4h`nB37Iu;N@~9Thj3$xlO~- zSA#<xR)McrLIu~XK9%xvk?^7*X{V$3(V!xd;)^mZzM`m68Fk7=@nt0WHp!xfV$nn_ z4q2=cOSQIAA#Z@Qc1_9}naFS?HmoE<aVZv6qNrV(TgjCL_)7}p>PLazxDyJ6gw-mD zZ>d;<A*Wn{AwYnF3rp3tG`WH~na@@3qUa8dtwEE792LaKup|#hqM<}AqRI;LDO1V2 zsjMk|B!j12(f|ypMT15@IUb5bZAKEvCtGR|$>4UkejaI96+;n8RuvKXBr}hM#=r+J z$unW{Cjo!p%_1=@t07T|M`RWF(`%JBje&4dt7LE~yqpaOP#j$J5-edm7G+pbhSgX| zQe`<F2X1Gx$$b8<Fc1c}=I{VHPlMN9lJi8JoQf2R$6}Hg1)eV#VR&C5G9Cz*^=HVh zf;(T5|9DM)X;_v+iWrqe6}3udljW>1mo2Qrwbxk`0%yl0*P%MOB#@LW#p4OIL%y8L zWK+o!lEK|Cfw$BKkrI?o8iszL#G~;<9PN;%lDRcO`)JVbe<zpW@Sorp@ipAf|0DlN z{s;Lhyny~5eFRm|GiVR@W$q^d<W>J7JsMvDQVwuLBC0_V_=*y~lz2#%<VZAzymG#n zPUcsN<;rke6h(AK(2H}tCL2_`qQ)X}%-&G=(G?gAL4TKwaG^-Im97{RfpkQGCL@6l zltf610s;lK%hTE00=Z90>oREYDJ@$UW!K0SA6B8gK_87p5@d*qpM@+)KB6<JbxsN3 z;{tRWD4ryT#Ap=yC-TM2aYIGV9M<ymBPbXfHX{NsMTQO-He;d!^015>;NjXR8MzTH zq#V*Qm;<kd0Y=eSNQ{Yc3^2sakq2BuDF-*nB!(oA1{tnmmP|5I4m8dr!`K>+Mk5mH zj2f9B4k`O<Gil!i7_pR)EQ45pJ@CNDTzC`DRf@lHCK<{kDT*9LovI}hjHmmwOtoL2 z*szocscKY_MbruYC>bRfwYxUS5)Da;6otlTkv>q_yGa%~6qBNHRke@W&+O5%oYDKP z<<qFBP{+|&ERObAN+SdXgG(Y0X?G){(P23nimOpo7117B(K<KDB8L*t{ozBn$NE7c z-+zSvj)On<=Sskpz!NEf{opOE6P*8czvEpk1^D`N^!h|t@|B7HpL_rJ6ItnQp<D@U zA_1}&*h1(3?c6mEe-ghRzYQPezr?@DU*dP6KSA$BXSr{3KM#qo;&(o*O+~^;GA8ff ze-KubG2(wP5r;{10_OZ=qArKnrb;MXEb!As@Wq|YXUc-+^EeYaAKC<$5{gC?B^G^1 zTo;2nu2VI9sW4$AizF3!CBm0v<4a#!WQt@26_RTifzHLphBS<Q&XS5Tvg(4Bvn;{x zgLOSyr;MY68kQbA7Fd|VY!B|nQPhYE>xcy9ODGkKl{!d9o~B4T`%u7IIEn=JW1w&` z6*e&>@iLSSHd81Xy<GIxv(TA<hQeQm4>2B!DY67>NI;QUTFTt2!^6aYR**0nbnpNh z7LiaaBF4pd-OAD#(F7bibG(+5DA_531ubv_YxM}+qP7VqXO1;O0Gk>TtRJHhXf~T6 z=&y@FCi?|YC!!ozB4nqcp)7(&bp+OhFDwofnQS<SA~apnG&BTA>Z9P=cA9ma40~g; z7*Z1=Spiww06NpFW$7bJNoy8ZTC1>Djl)t4)~dF~r^}f%r4Zf!M*@cg{xkR({^3{A z)t~4r4+012ZGA5k9ES?lo50Eb5^PUHV2$muZyeVLdenVmN}$31{2O(gP<yG+mZu3@ zTst=;B=eO;dfSk3A0RojsB`tukdW4HFfwjdlp8<>t{rOj2fER1$Jqq24L5|}+vvbS zvmhr&OeQQGv(V_k%3-fx=|&qq2WrEt*~rt^2)_a9IK3cS_GVgO?Fg75110Sma0Bfk zT<eow$z~Q|&Td2=ZA8lgT!)%9mG1w$_y0c8Lzr7QR{}K>aPR-F5s4e&N?_Yaz_|Y# zO5DV)aPaqAaDey)zRZ2$jS#}r*=B$8M5C(=8z@yQN(~aO-5vG%!(p`1Q(vK@CfjxU zT)Zazp{L=X1Jg6+^-rBZ8xuASCvv!MQ6^cG(&@OU#F90nG-Z>w+UIT!pbRW_w>b`4 zWD03U5yha5gX7>k8+bgiDUVTERzx|`fcV=UjzxxKOAg6$lPI$U9<-hVCqpCXg>J`^ z%5YcB+{haf-I^P}->`eV4HmXmyP=@ELvkY@sSAs0mN~Pp)ep1k@EApP<bPdMyX^P3 z%a-MwrvHQRKXdTs{#*&T64*u(;1N&n|Ms9NhpK!(|7ZBuICX0Q+&}%C*MH^=dS3Gd zXpCKp<hD<;sZ%q4I}$SXuW>^J5B*gZMy|}wOcJkXQ{&TfY#)qpqUqTh>a=gv4%s6q z+`<$hIN|kQhATNPJNA=|&xn4JN-7#tVGlQ9ipUA_@b{?bxExzTH6K^<2{NeAFZRaM z&uaWmZN+a?S(0K&DcYFdhrd2V$MrD$n%~*L#=<0>8{SXS=>^k{E##I<Nuuyru8Bz5 zTVqW+`y|(Xz%2^ijs__7f=;rzOG|ewb=_Uiza{5JjZ>*Qa~3qpGoZ9o$rZ9j^9@`) z-|Qb8L<_WJ<(r_pnO!VrZ&tHw>8#^5Z7Y={ae#0z1UaeyKll89>oL!Ta3%0$Nq|}k zQTt!F|36tZ>z2lqz}6Db`ae1U_i?|*;g91Amid3>f0e%uy8r(Zy&GMD=r`GK<LIzv z3?re9Bq%&M?llGN?L<V3fF+3ZELdNVNvKd<6R5U}#E)b$U>QJXwxD5@&kDU$*-S2Z z4jxB~YZb7UIk|r0lr#jUM#NY6sf&=E#nfUuJ;W?1P7!UOAwfS8KP8>+4TTe$R>l!( zLEvB#E?)%&|AdJ4O8PaeXeO>HiUiRKLyZHprND$hB_=*1n0kP&w@;ETS5wwP$%a_~ z)!v~>N#w*jG!fGg+O%*eLSj1sc6}lk^bmwLDVYe9U><ZU8;VDDM5YRh&Y2{I5=u-3 zJ+3;4(4~l$Q>rNw=<mcr2{9Il6V(*4Mz|&uj#6DzDawvol%P@*1tlp(P7r;X8jMms zIT7_2NzpJ;`vImuqZN-R>4cQ1l#oGV%A$6KpOLk4SygVRW}6xZi!5St0EQ`~T=kT! zsLsupq!A6+Riq-rfI$XpqIg0AT`z|{j9CPxA2lX6#v(;SQ3Z6yh$fres>Tom!$SH$ zMyniJ<<r>9-F(A4{KhSB)71TUj7V}?g#Y48>XIU<5hb-m6uJ~8l1apuQc`wmbwrw; zn9Wa3oL`w5n-r&4NA69puE6`Ga(yh5pSe1D58~CS)n)Pe+|<3P!qmNmdpAc$)}%Wl zmsjS;^NE$rwb|k|W&U34^=s#s77FK9lk$A^`m^Js^Oy5Cl7(~C>vFuhASbGsXV0%M z<RUb~g~Iuj1-X(>6=v^UxFOxTJ~3auWab@foxdb4EnJ%yljjmrTAsgqP0rs)Uz)uz za_vgBRqwts7y^Q-8f`_<m<(01af_z~Pp2eNmBn;MRO3li&c;Pal#?nv$xEq7OnLkZ zu32`860zAy#1b1lxM^zR(nwqt<!EXt6-}fvvYLSUPpX;NlDq_mB*ZjjdhYz{%*2#B zGj~OqUOm4$b#+Rd8Cy_h<`$%xu}p5^>U4g3Zu#Ey)hqIXJfEMMyPlhwV>Ld1<+;qn z{JqS?^sSU!S%(^jTE28$Nh#+`*RRgr8BwO}l_P>0>M+<9scH;HqK#Wkv~qwsB^{5X zlt@;U)TAl`yHYA1Uy^|JOf>QMR}N?&$}r3%U;qXqtVA2}{mXrX<9`r+i2DfYd&B$x z>q1~-xeco8Z6n2WJh>*NB5Jad7gMEDR*WxK<F^W{cgpeTYBn)FH=kdS&*vAeo?n@s z8;MM<UXiBe=5I_-Tv2AOUV;Gxn%Bg*GBtKZxjvUx7go;}7UtGtla|55Hg=3oMkfoi zHy5r()>3yPt0_4mrVIJpg~B;0GqGGX$C#<=+||U5>sRlLLbHVy7`ZW-yPdlx6S$S7 z%(dx!I-gj-4)~_7i9{6{W(hJgPZULBC8vUAovdsu`)ElENoi%d6c_I$N;eDfd!^+& z<>h=%y%Ar&y?i@b6(75jO2mAZ43S{#7Lg)keB7oV2Ivv*+GrXn#FJ8PX{l0NizPE^ zIhwzfQ*Kt5;?Ybbm0FF*XC@ZzLHo*2k1a?GtK)YU<Vk3+Q@5uJ<FqYLPfXsK8JjOm z%hzvAUA+>Sx;J}+wB@Bsr|PsXka`R(XeG`5Z-K)LuS>^tk+>3YB|s#war8vPr7E!w z4@puaAvaj9Jls-MevM028J4P~|GW495+S%hR|4Bl0&f4`es%7a*p+}T0k{9_l5qcZ zC9wS@K>UBW^Z)Hv?{0}*2@na8??2D)<M@5}sw)v!0-6L|4e#tS=n6N|(bb$j>nb0$ zE|o#U``87q|I!(>G3n5lc4)#c#>6Eltx8E#VcG$aWqQ1m(_`b;EY1m>%Jv2(r@FKQ zAJJyEXiL-nkAI58pM}8vxe{<C@TQS~INroXP+~N>CV-Q2@Eb3XzDzyG`?Uz?ARvwz QInvY<t|f;S;mq;>0X<qg*8l(j diff --git a/example/manage.py b/example/manage.py deleted file mode 100755 index 729887ecd..000000000 --- a/example/manage.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -sys.path.insert( - 0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings') - -from django.core.management import execute_from_command_line - -execute_from_command_line(sys.argv) diff --git a/example/management/__init__.py b/example/management/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/example/management/commands/__init__.py b/example/management/commands/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/example/management/commands/generate_big_tree.py b/example/management/commands/generate_big_tree.py deleted file mode 100644 index 3e4361c1a..000000000 --- a/example/management/commands/generate_big_tree.py +++ /dev/null @@ -1,41 +0,0 @@ -# ------------------------------------------------------------------------ -# coding=utf-8 -# ------------------------------------------------------------------------ - -from django.core.management.base import NoArgsCommand - -from feincms.module.page.models import Page - - -class Command(NoArgsCommand): - help = ( - "Run this command to generate a big tree for performance testing" - " purposes.") - - def handle_noargs(self, **options): - parents = [None] * 5 - - Page.objects.all().delete() - - for i1 in range(5): - parents[0] = Page.objects.create( - title='Page %s' % (i1,), - ) - - for i2 in range(5): - parents[1] = Page.objects.create( - title='Page %s.%s' % (i1, i2), - parent=parents[0], - ) - - for i3 in range(5): - parents[2] = Page.objects.create( - title='Page %s.%s.%s' % (i1, i2, i3), - parent=parents[1], - ) - - for i4 in range(5): - parents[3] = Page.objects.create( - title='Page %s.%s.%s.%s' % (i1, i2, i3, i4), - parent=parents[2], - ) diff --git a/example/media/.gitignore b/example/media/.gitignore deleted file mode 100644 index 72e8ffc0d..000000000 --- a/example/media/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/example/models.py b/example/models.py deleted file mode 100644 index 629400369..000000000 --- a/example/models.py +++ /dev/null @@ -1,122 +0,0 @@ -from django import forms -from django.db import models -from django.utils.encoding import python_2_unicode_compatible -from django.utils.text import capfirst -from django.utils.translation import ugettext_lazy as _ - -from mptt.models import MPTTModel - -from feincms.module.blog.models import Entry, EntryAdmin -from feincms.module.page.models import Page -from feincms.content.richtext.models import RichTextContent -from feincms.content.raw.models import RawContent -from feincms.content.image.models import ImageContent -from feincms.content.medialibrary.models import MediaFileContent -from feincms.content.application.models import ApplicationContent -from feincms.module.page.extensions.navigation import ( - NavigationExtension, PagePretender) -from feincms.content.application.models import app_reverse - - -Page.register_templates({ - 'key': 'base', - 'title': 'Base Template', - 'path': 'base.html', - 'regions': ( - ('main', 'Main region'), - ('sidebar', 'Sidebar', 'inherited'), - ), -}) -Page.create_content_type(RichTextContent) -Page.create_content_type(RawContent) -Page.create_content_type( - MediaFileContent, - TYPE_CHOICES=( - ('default', 'Default position'), - ), -) -Page.create_content_type( - ImageContent, - POSITION_CHOICES=( - ('default', 'Default position'), - ), -) - - -def get_admin_fields(form, *args, **kwargs): - return { - 'exclusive_subpages': forms.BooleanField( - label=capfirst(_('exclusive subpages')), - required=False, - initial=form.instance.parameters.get('exclusive_subpages', False), - help_text=_( - 'Exclude everything other than the application\'s' - ' content when rendering subpages.'), - ), - } - - -Page.create_content_type(ApplicationContent, APPLICATIONS=( - ('blog_urls', 'Blog', { - 'admin_fields': get_admin_fields, - 'urls': 'example.blog_urls', - }), -)) - - -Entry.register_regions( - ('main', 'Main region'), -) -Entry.create_content_type(RawContent) -Entry.create_content_type( - ImageContent, - POSITION_CHOICES=( - ('default', 'Default position'), - ) -) - - -class BlogEntriesNavigationExtension(NavigationExtension): - """ - Extended navigation for blog entries. - - It would be added to 'Blog' page properties in admin. - """ - name = _('all blog entries') - - def children(self, page, **kwargs): - for entry in Entry.objects.all(): - yield PagePretender( - title=entry.title, - url=app_reverse( - 'blog_entry_detail', 'blog_urls', kwargs={'pk': entry.id}), - level=page.level + 1, - ) - -Page.register_extensions( - 'feincms.module.page.extensions.navigation', - 'feincms.module.page.extensions.sites', -) - - -@python_2_unicode_compatible -class Category(MPTTModel): - name = models.CharField(max_length=20) - slug = models.SlugField() - parent = models.ForeignKey( - 'self', blank=True, null=True, related_name='children') - - class Meta: - ordering = ['tree_id', 'lft'] - verbose_name = 'category' - verbose_name_plural = 'categories' - - def __str__(self): - return self.name - - -# add m2m field to entry so it shows up in entry admin -Entry.add_to_class( - 'categories', - models.ManyToManyField(Category, blank=True, null=True)) -EntryAdmin.list_filter += ('categories',) diff --git a/example/settings.py b/example/settings.py deleted file mode 100644 index b1f2d9c2b..000000000 --- a/example/settings.py +++ /dev/null @@ -1,95 +0,0 @@ -# Django settings for example project. - -import os - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - # ('Your Name', 'your_email@domain.com'), -) - -MANAGERS = ADMINS - -DATABASE_ENGINE = 'sqlite3' -DATABASE_NAME = os.path.join(os.path.dirname(__file__), 'example.db') - -DATABASES = {'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': DATABASE_NAME, -}} - -TIME_ZONE = 'America/Chicago' - -LANGUAGE_CODE = 'en-us' - -SITE_ID = int(os.environ.get('SITE_ID', 1)) - -USE_I18N = True - -MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media/') -MEDIA_URL = '/media/' -STATIC_ROOT = os.path.join(os.path.dirname(__file__), 'static/') -STATIC_URL = '/static/' - -SECRET_KEY = '_wn95s-apfd-442cby5m^_^ak6+5(fyn3lvnvtn7!si&o)1x^w' - -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', - 'django.core.context_processors.request', - 'django.core.context_processors.static', - - 'feincms.context_processors.add_page_if_missing', -) - -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', -) - -ROOT_URLCONF = 'example.urls' - -TEMPLATE_DIRS = ( -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.admin', - 'django.contrib.staticfiles', - - 'feincms', - 'feincms.module.blog', - 'feincms.module.page', - 'feincms.module.medialibrary', - 'example', - - 'mptt', -) - -LANGUAGES = ( - ('en', 'English'), - ('de', 'German'), -) - -FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS = True - -from feincms.content.application.models import app_reverse -ABSOLUTE_URL_OVERRIDES = { - 'blog.entry': lambda entry: app_reverse( - 'blog_entry_detail', 'blog_urls', - args=(entry.id,)), -} diff --git a/example/templates/404.html b/example/templates/404.html deleted file mode 100644 index 81b0d6084..000000000 --- a/example/templates/404.html +++ /dev/null @@ -1 +0,0 @@ -<h1>Page not found</h1> diff --git a/example/templates/base.html b/example/templates/base.html deleted file mode 100644 index 4e43966a3..000000000 --- a/example/templates/base.html +++ /dev/null @@ -1,118 +0,0 @@ -{% load applicationcontent_tags feincms_tags feincms_page_tags %} -<html> -<head> - <title>{{ feincms_page.title }} - - - -

{{ feincms_page.title }}

- - - -
-
-

Main content

- {% block content %}{% feincms_render_region feincms_page "main" request %}{% endblock %} -
- - -
- - {% feincms_frontend_editing feincms_page request %} - - {% get_fragment request "something" %} - - diff --git a/example/templates/blog/entry_detail.html b/example/templates/blog/entry_detail.html deleted file mode 100644 index 4903fdf66..000000000 --- a/example/templates/blog/entry_detail.html +++ /dev/null @@ -1,11 +0,0 @@ -{% load i18n %} -{% load feincms_tags applicationcontent_tags %} - -
-

{{object.title}}

- {% feincms_render_region object "main" request %} -
- -

- {% trans "All entries" %} -

diff --git a/example/templates/blog/entry_list.html b/example/templates/blog/entry_list.html deleted file mode 100644 index 8a6d2b49a..000000000 --- a/example/templates/blog/entry_list.html +++ /dev/null @@ -1,5 +0,0 @@ -{% load applicationcontent_tags %} - -{% for object in object_list %} -

{{ object.title }}

-{% endfor %} diff --git a/example/urls.py b/example/urls.py deleted file mode 100644 index 5cba5b068..000000000 --- a/example/urls.py +++ /dev/null @@ -1,16 +0,0 @@ -import os - -from django.conf.urls import patterns, include, url -from django.contrib import admin -from django.contrib.staticfiles.urls import staticfiles_urlpatterns - -admin.autodiscover() - -urlpatterns = patterns( - '', - url(r'^admin/', include(admin.site.urls)), - url(r'^media/(?P.*)$', 'django.views.static.serve', { - 'document_root': os.path.join(os.path.dirname(__file__), 'media/')}), - url(r'', include('feincms.contrib.preview.urls')), - url(r'', include('feincms.urls')) -) + staticfiles_urlpatterns() diff --git a/quickstart.sh b/quickstart.sh deleted file mode 100755 index c65d8b233..000000000 --- a/quickstart.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -# -# This script downloads all the software needed to run FeinCMS -# - -cd example -virtualenv venv -. venv/bin/activate -pip install Django django-mptt Pillow - -cat < Date: Tue, 22 Jul 2014 15:29:19 +0200 Subject: [PATCH 1008/1590] Deprecate RSSContent --- docs/deprecation.rst | 6 ++++++ docs/releases/1.11.rst | 6 ++++++ feincms/content/rss/models.py | 8 +++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index 81cabf78a..a6617d0c3 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -107,3 +107,9 @@ will be issued for at least two releases. ==== No deprecations. + + +1.11 +==== + +* ``RSSContent`` and ``update_rsscontent`` have been deprecated. diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst index 38e917c90..3f54fdf20 100644 --- a/docs/releases/1.11.rst +++ b/docs/releases/1.11.rst @@ -20,6 +20,12 @@ Removal of deprecated features New deprecations ================ +* ``RSSContent`` and ``update_rsscontent`` have been deprecated, those being + the only reason why ``FeinCMS`` depends on ``feedparser``. This will allow + us to remove this dependency. Users should switch to + `feincms-syndication `_ + instead. + Notable features and improvements ================================= diff --git a/feincms/content/rss/models.py b/feincms/content/rss/models.py index 70353d1af..933d72b99 100644 --- a/feincms/content/rss/models.py +++ b/feincms/content/rss/models.py @@ -1,5 +1,7 @@ from __future__ import absolute_import, unicode_literals +import feedparser +import warnings import time from django.db import models @@ -8,7 +10,11 @@ from django.utils.translation import ugettext_lazy as _ from django.template.loader import render_to_string -import feedparser + +warnings.warn( + 'RSSContent has been deprecated.' + ' Please use https://github.com/feincms/feincms-syndication instead.', + DeprecationWarning, stacklevel=2) class RSSContent(models.Model): From fcfc5094591ff9d79dabb0255a111e17a700acde Mon Sep 17 00:00:00 2001 From: Gwildor Sok Date: Mon, 28 Jul 2014 14:49:07 +0200 Subject: [PATCH 1009/1590] Allow more fields to be optional in custom Page admins. See issue #536. When using a custom Page model and corresponding admin class and still using the original PageAdminForm, you couldn't disable the redirect_to and override_url (and less important: active) fields because the form did not check first if they were in the fieldset or not. --- feincms/module/page/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 228feeb71..adbdbdf6c 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -114,7 +114,7 @@ def __init__(self, *args, **kwargs): # Not required, only a nice-to-have for the `redirect_to` field modeladmin = kwargs.pop('modeladmin', None) super(PageAdminForm, self).__init__(*args, **kwargs) - if modeladmin: + if modeladmin and 'redirect_to' in self.fields: # Note: Using `parent` is not strictly correct, but we can be # sure that `parent` always points to another page instance, # and that's good enough for us. @@ -172,7 +172,7 @@ def clean(self): cleaned_data['redirect_to'] = '%s.%s:%s' % ( opts.app_label, get_model_name(opts), redirect_to) - if not cleaned_data['active']: + if 'active' in cleaned_data and not cleaned_data['active']: # If the current item is inactive, we do not need to conduct # further validation. Note that we only check for the flag, not # for any other active filters. This is because we do not want @@ -180,7 +180,7 @@ def clean(self): # really won't be active at the same time. return cleaned_data - if cleaned_data['override_url']: + if 'override_url' in cleaned_data and cleaned_data['override_url']: if active_pages.filter( _cached_url=cleaned_data['override_url']).count(): self._errors['override_url'] = ErrorList([ From df4589ce7c6453ef9b5b0e82c1a1a3f5d7ad892c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 8 Aug 2014 11:44:43 +0200 Subject: [PATCH 1010/1590] Allow explicit specification of navigation extensions, deprecate the auto-discovery behavior --- docs/deprecation.rst | 3 ++ docs/integration.rst | 17 ++++-- docs/releases/1.11.rst | 3 ++ feincms/module/page/extensions/navigation.py | 56 ++++++++++++++++++-- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index a6617d0c3..94c4b47c5 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -113,3 +113,6 @@ No deprecations. ==== * ``RSSContent`` and ``update_rsscontent`` have been deprecated. + +* The automatic discovery of subclasses of ``NavigationExtension`` has been + replaced with an explicit mechanism of defining navigation extensions. diff --git a/docs/integration.rst b/docs/integration.rst index 6883bfd2e..ad536471f 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -438,26 +438,33 @@ You don't need to do anything else as long as you use the built-in :: - from feincms.module.page.extensions.navigation import NavigationExtension, PagePretender + from feincms.module.page.extensions import navigation - class BlogCategoriesNavigationExtension(NavigationExtension): + class BlogCategoriesNavigationExtension(navigation.NavigationExtension): name = _('blog categories') def children(self, page, **kwargs): for category in Category.objects.all(): - yield PagePretender( + yield navigation.PagePretender( title=category.name, url=category.get_absolute_url(), ) - class PassthroughExtension(NavigationExtension): + class PassthroughExtension(navigation.NavigationExtension): name = 'passthrough extension' def children(self, page, **kwargs): for p in page.children.in_navigation(): yield p - Page.register_extensions('feincms.module.page.extensions.navigation') + class MyExtension(navigation.Extension): + navigation_extensions = [ + BlogCategoriesNavigationExtension, + PassthroughExtension, + # Alternatively, a dotted Python path also works. + ] + + Page.register_extensions(MyExtension) Note that the objects returned should at least try to mimic a real page so navigation template tags as ``siblings_along_path_to`` and friends continue diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst index 3f54fdf20..e418ad8ee 100644 --- a/docs/releases/1.11.rst +++ b/docs/releases/1.11.rst @@ -26,6 +26,9 @@ New deprecations `feincms-syndication `_ instead. +* The automatic discovery of subclasses of ``NavigationExtension`` has been + replaced with an explicit mechanism of defining navigation extensions. + Notable features and improvements ================================= diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 3edb296b2..e29e82337 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -9,8 +9,13 @@ from __future__ import absolute_import, unicode_literals +import types +import warnings + from django.db import models from django.utils import six +from django.utils.datastructures import SortedDict +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from feincms import extensions @@ -105,30 +110,71 @@ def navigation_extension_choices(): yield ('%s.%s' % (ext.__module__, ext.__name__), ext.name) +def get_extension_class(extension): + extension = get_object(extension) + if isinstance(extension, types.ModuleType): + return getattr(extension, 'Extension') + return extension + + class Extension(extensions.Extension): ident = 'navigation' # TODO actually use this + navigation_extensions = None + + @cached_property + def _extensions(self): + if self.navigation_extensions is None: + warnings.warn( + 'Automatic registering of navigation extensions has been' + ' deprecated. Please inherit the extension and put a list' + ' of dotted python paths into the navigation_extensions' + ' class variable.', DeprecationWarning, stacklevel=3) + + return SortedDict( + ('%s.%s' % (ext.__module__, ext.__name__), ext) + for ext in NavigationExtension.types + if ( + issubclass(ext, NavigationExtension) + and ext is not NavigationExtension)) + + else: + return SortedDict( + ('%s.%s' % (ext.__module__, ext.__name__), ext) + for ext + in map(get_extension_class, self.navigation_extensions)) def handle_model(self): + choices = [ + (path, ext.name) for path, ext in self._extensions.items()] + self.model.add_to_class( 'navigation_extension', models.CharField( _('navigation extension'), - choices=navigation_extension_choices(), + choices=choices, blank=True, null=True, max_length=200, help_text=_( 'Select the module providing subpages for this page if' ' you need to customize the navigation.'))) + extension = self + @monkeypatch_method(self.model) def extended_navigation(self, **kwargs): if not self.navigation_extension: return self.children.in_navigation() - cls = get_object(self.navigation_extension, fail_silently=True) - if not cls or not callable(cls): - return self.children.in_navigation() + cls = None + + try: + cls = extension._extensions[self.navigation_extension] + except KeyError: + cls = get_object(self.navigation_extension, fail_silently=True) + extension._extensions[self.navigation_extension] = cls - return cls().children(self, **kwargs) + if cls: + return cls().children(self, **kwargs) + return self.children.in_navigation() def handle_modeladmin(self, modeladmin): modeladmin.add_extension_options(_('Navigation extension'), { From d4db5b8ea90853339e2e0b6bdc9f40465de68e6f Mon Sep 17 00:00:00 2001 From: feczo Date: Thu, 21 Aug 2014 10:50:48 +1000 Subject: [PATCH 1011/1590] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index eaf821366..87d53481d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2013, FEINHEIT GmbH and individual contributors. +Copyright (c) 2009-2014, FEINHEIT GmbH and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, From da4026ebc11d64e6ae3ef5ca323156362f421ee2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 3 Sep 2014 08:35:07 +0200 Subject: [PATCH 1012/1590] Add Django 1.7 to Travis --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1e8ec7a2c..45bc65e53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,11 @@ env: - DJANGO_REQUIREMENT="Django>=1.4,<1.5" - DJANGO_REQUIREMENT="Django>=1.5,<1.6" - DJANGO_REQUIREMENT="Django>=1.6,<1.7" + - DJANGO_REQUIREMENT="Django>=1.7,<1.8" matrix: exclude: + - python: "2.6" + env: DJANGO_REQUIREMENT="Django>=1.7<1.8" - python: "3.2" env: DJANGO_REQUIREMENT="Django>=1.4,<1.5" - python: "3.3" From b1a4e63a6a41ac2dec2b22128dfbf53b05d46f0a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 3 Sep 2014 08:37:56 +0200 Subject: [PATCH 1013/1590] Fix a dumb typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 45bc65e53..f98a3e9ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ env: matrix: exclude: - python: "2.6" - env: DJANGO_REQUIREMENT="Django>=1.7<1.8" + env: DJANGO_REQUIREMENT="Django>=1.7,<1.8" - python: "3.2" env: DJANGO_REQUIREMENT="Django>=1.4,<1.5" - python: "3.3" From 78dcf3550d90808cebf9568513ddb7193628e91d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Sep 2014 10:33:55 +0200 Subject: [PATCH 1014/1590] Drop compatibility with Django < 1.6, less deprecation warnings Also fixes #548 (RemovedInDjango18Warning regarding get_query_set). --- .travis.yml | 7 +-- docs/releases/1.11.rst | 3 +- feincms/admin/tree_editor.py | 4 +- feincms/module/medialibrary/models.py | 4 +- feincms/utils/__init__.py | 5 +- feincms/utils/queryset_transform.py | 4 +- setup.py | 3 +- tests/tox.ini | 85 ++------------------------- 8 files changed, 15 insertions(+), 100 deletions(-) diff --git a/.travis.yml b/.travis.yml index f98a3e9ad..9a870bd26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,19 +4,14 @@ python: - "2.7" - "3.2" - "3.3" + - "3.4" env: - - DJANGO_REQUIREMENT="Django>=1.4,<1.5" - - DJANGO_REQUIREMENT="Django>=1.5,<1.6" - DJANGO_REQUIREMENT="Django>=1.6,<1.7" - DJANGO_REQUIREMENT="Django>=1.7,<1.8" matrix: exclude: - python: "2.6" env: DJANGO_REQUIREMENT="Django>=1.7,<1.8" - - python: "3.2" - env: DJANGO_REQUIREMENT="Django>=1.4,<1.5" - - python: "3.3" - env: DJANGO_REQUIREMENT="Django>=1.4,<1.5" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q $DJANGO_REQUIREMENT django-mptt Pillow feedparser flake8 --use-mirrors diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst index 3f54fdf20..f4ec22326 100644 --- a/docs/releases/1.11.rst +++ b/docs/releases/1.11.rst @@ -42,5 +42,4 @@ Bugfixes Compatibility with Django and other apps ======================================== -FeinCMS 1.11 requires Django 1.4 or better. The testsuite is successfully run -against Django 1.4, 1.5, 1.6 and the upcoming 1.7. +FeinCMS 1.11 requires Django 1.6 or better. diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index be2228c37..87fad9867 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -157,9 +157,9 @@ def __init__(self, request, *args, **kwargs): self.user = request.user super(ChangeList, self).__init__(request, *args, **kwargs) - def get_query_set(self, *args, **kwargs): + def get_queryset(self, *args, **kwargs): mptt_opts = self.model._mptt_meta - qs = super(ChangeList, self).get_query_set(*args, **kwargs).\ + qs = super(ChangeList, self).get_queryset(*args, **kwargs).\ order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr) # Force has_filters, so that the expand/collapse in sidebar is visible self.has_filters = True diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 0ef9debd8..e796afc1a 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -29,8 +29,8 @@ class CategoryManager(models.Manager): Simple manager which exists only to supply ``.select_related("parent")`` on querysets since we can't even __str__ efficiently without it. """ - def get_query_set(self): - return super(CategoryManager, self).get_query_set().select_related( + def get_queryset(self): + return super(CategoryManager, self).get_queryset().select_related( "parent") diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index dc9c69f27..a5dd7f927 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -4,10 +4,7 @@ from __future__ import absolute_import, division, unicode_literals -try: - from hashlib import md5 -except ImportError: - import md5 +from hashlib import md5 from django.conf import settings as django_settings from django.core.exceptions import ImproperlyConfigured diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index c6acf4a31..6dce84b0d 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -119,8 +119,8 @@ class TransformManager(models.Manager): def get_queryset(self): return TransformQuerySet(self.model, using=self._db) - def get_query_set(self): + def get_queryset(self): return TransformQuerySet(self.model, using=self._db) def transform(self, *fn): - return self.get_query_set().transform(*fn) + return self.get_queryset().transform(*fn) diff --git a/setup.py b/setup.py index dfa5e9d9c..7bbf34881 100755 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ def read(filename): ], }, install_requires=[ - 'Django>=1.4.2', + 'Django>=1.6', 'django-mptt>=0.6.0', 'Pillow>=2.0.0', 'feedparser>=5.0.0', @@ -54,6 +54,7 @@ def read(filename): 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Application Frameworks', diff --git a/tests/tox.ini b/tests/tox.ini index 98a68379c..ea14232e8 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -2,20 +2,13 @@ setupdir = .. distribute = False envlist = - py26-1.4.X, - py26-1.5.X, py26-1.6.X, - py27-1.4.X, - py27-1.5.X, py27-1.6.X, py27-1.7.X, - py32-1.5.X, py32-1.6.X, py32-1.7.X, - py33-1.5.X, py33-1.6.X, py33-1.7.X, - py34-1.5.X, py34-1.6.X, py34-1.7.X, @@ -25,46 +18,6 @@ commands = setenv = PYTHONPATH = .:{toxworkdir}/../.. -[testenv:py26-1.4.X] -basepython = python2.6 -deps = - django==1.4.7 - django-mptt==0.6.0 - Pillow==2.4.0 - feedparser==5.1.3 - lxml==3.2.3 - BeautifulSoup==3.2.1 - -[testenv:py27-1.4.X] -basepython = python2.7 -deps = - django==1.4.7 - django-mptt==0.6.0 - Pillow==2.4.0 - feedparser==5.1.3 - lxml==3.2.3 - BeautifulSoup==3.2.1 - -[testenv:py26-1.5.X] -basepython = python2.6 -deps = - django==1.5.3 - django-mptt==0.6.0 - Pillow==2.4.0 - feedparser==5.1.3 - lxml==3.2.3 - BeautifulSoup==3.2.1 - -[testenv:py27-1.5.X] -basepython = python2.7 -deps = - django==1.5.3 - django-mptt==0.6.0 - Pillow==2.4.0 - feedparser==5.1.3 - lxml==3.2.3 - BeautifulSoup==3.2.1 - [testenv:py26-1.6.X] basepython = python2.6 deps = @@ -88,23 +41,13 @@ deps = [testenv:py27-1.7.X] basepython = python2.7 deps = - https://github.com/django/django/zipball/stable/1.7.x + Django==1.7 django-mptt==0.6.1 Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 BeautifulSoup==3.2.1 -[testenv:py32-1.5.X] -basepython = python3.2 -deps = - Django==1.5.4 - django-mptt==0.6.0 - Pillow==2.4.0 - feedparser==5.1.3 - lxml==3.2.3 - beautifulsoup4==4.3.1 - [testenv:py32-1.6.X] basepython = python3.2 deps = @@ -118,23 +61,13 @@ deps = [testenv:py32-1.7.X] basepython = python3.2 deps = - https://github.com/django/django/zipball/stable/1.7.x + Django==1.7 django-mptt==0.6.1 Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 -[testenv:py33-1.5.X] -basepython = python3.3 -deps = - Django==1.5.4 - django-mptt==0.6.0 - Pillow==2.4.0 - feedparser==5.1.3 - lxml==3.2.3 - beautifulsoup4==4.3.1 - [testenv:py33-1.6.X] basepython = python3.3 deps = @@ -148,23 +81,13 @@ deps = [testenv:py33-1.7.X] basepython = python3.3 deps = - https://github.com/django/django/zipball/stable/1.7.x + Django==1.7 django-mptt==0.6.1 Pillow==2.4.0 feedparser==5.1.3 lxml==3.2.3 beautifulsoup4==4.3.1 -[testenv:py34-1.5.X] -basepython = python3.4 -deps = - Django==1.5.4 - django-mptt==0.6.0 - Pillow==2.4.0 - feedparser==5.1.3 - lxml==3.2.3 - beautifulsoup4==4.3.1 - [testenv:py34-1.6.X] basepython = python3.4 deps = @@ -178,7 +101,7 @@ deps = [testenv:py34-1.7.X] basepython = python3.4 deps = - https://github.com/django/django/zipball/stable/1.7.x + Django==1.7 django-mptt==0.6.1 Pillow==2.4.0 feedparser==5.1.3 From ed3e405a424af7152f67c5b0f7578474888e9ef1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Sep 2014 10:36:10 +0200 Subject: [PATCH 1015/1590] Pillow has been out long enough to drop the old "import Image" fallback --- feincms/templatetags/feincms_thumbnail.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 2682f6af3..b040224e6 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -5,20 +5,9 @@ from __future__ import absolute_import, unicode_literals from io import BytesIO +from PIL import Image import re -# Try to import PIL in either of the two ways it can end up installed. -try: - from PIL import Image -except ImportError: - try: - import Image - except ImportError: - # Django seems to silently swallow the ImportError under certain - # circumstances. Raise a generic exception explaining why we are - # unable to proceed. - raise Exception('FeinCMS requires PIL to be installed') - from django import template from django.utils.encoding import force_text, python_2_unicode_compatible from django.core.files.storage import default_storage From 8f179401b8d1eb8b1dc0e65069f75f2026f3b608 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Sep 2014 10:45:41 +0200 Subject: [PATCH 1016/1590] Loading the URL template tag from future is not necessary anymore --- tests/testapp/templates/alias_reverse_test.html | 2 +- tests/testapp/templates/full_reverse_test.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testapp/templates/alias_reverse_test.html b/tests/testapp/templates/alias_reverse_test.html index 6e2203626..0f6222033 100644 --- a/tests/testapp/templates/alias_reverse_test.html +++ b/tests/testapp/templates/alias_reverse_test.html @@ -1 +1 @@ -{% load applicationcontent_tags %}{% load url from future %}home:{% app_reverse "ac_module_root" "whatever" %} args:{% app_reverse "ac_args_test" "whatever" "xy" "zzy" %} base:{% url "feincms_handler" "test" %} +{% load applicationcontent_tags %}home:{% app_reverse "ac_module_root" "whatever" %} args:{% app_reverse "ac_args_test" "whatever" "xy" "zzy" %} base:{% url "feincms_handler" "test" %} diff --git a/tests/testapp/templates/full_reverse_test.html b/tests/testapp/templates/full_reverse_test.html index ab31b0f10..8120fb5e9 100644 --- a/tests/testapp/templates/full_reverse_test.html +++ b/tests/testapp/templates/full_reverse_test.html @@ -1 +1 @@ -{% load applicationcontent_tags %}{% load url from future %}home:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" %} args:{% app_reverse "ac_args_test" "testapp.applicationcontent_urls" "xy" "zzy" %} base:{% url "feincms_handler" "test" %} homeas:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" as reversed %}{{ reversed }} +{% load applicationcontent_tags %}home:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" %} args:{% app_reverse "ac_args_test" "testapp.applicationcontent_urls" "xy" "zzy" %} base:{% url "feincms_handler" "test" %} homeas:{% app_reverse "ac_module_root" "testapp.applicationcontent_urls" as reversed %}{{ reversed }} From ba65a452e21ec351a0f171ef20eb2869aa271a1b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Sep 2014 10:59:23 +0200 Subject: [PATCH 1017/1590] Remove more occurrences of loading the URL template tag from future --- feincms/templates/admin/feincms/_content_type_buttons.html | 1 - feincms/templates/admin/feincms/fe_tools.html | 1 - feincms/templates/admin/feincms/page/page/item_editor.html | 1 - feincms/templates/admin/feincms/recover_form.html | 1 - feincms/templates/admin/feincms/revision_form.html | 1 - feincms/templates/admin/medialibrary/mediafile/change_list.html | 1 - 6 files changed, 6 deletions(-) diff --git a/feincms/templates/admin/feincms/_content_type_buttons.html b/feincms/templates/admin/feincms/_content_type_buttons.html index 3f55699fd..29bc7b7ff 100644 --- a/feincms/templates/admin/feincms/_content_type_buttons.html +++ b/feincms/templates/admin/feincms/_content_type_buttons.html @@ -1,4 +1,3 @@ -{% load url from future %} {% load feincms_admin_tags %} - -{% include "admin/feincms/_messages_js.html" %} -{% include "admin/feincms/_regions_js.html" %} - -{% for inc in object.feincms_item_editor_includes.head %}{% include inc %}{% endfor %} - -{% endblock %} - -{% block content %} -
- -
-{% csrf_token %} -
-{% if is_popup %}{% endif %} - - - {{ form }} -
- -
- -
- -
-
- -
-{% endblock %} diff --git a/feincms/templates/admin/feincms/fe_editor_done.html b/feincms/templates/admin/feincms/fe_editor_done.html deleted file mode 100644 index f456048e1..000000000 --- a/feincms/templates/admin/feincms/fe_editor_done.html +++ /dev/null @@ -1,11 +0,0 @@ -{% include "admin/feincms/load-jquery.include" %} - -
- {{ content|safe }} -
- - diff --git a/feincms/templates/admin/feincms/fe_tools.html b/feincms/templates/admin/feincms/fe_tools.html deleted file mode 100644 index ac8023ff2..000000000 --- a/feincms/templates/admin/feincms/fe_tools.html +++ /dev/null @@ -1,39 +0,0 @@ -{% load i18n staticfiles %} - - - - - - - - - - diff --git a/feincms/templates/admin/feincms/page/page/item_editor.html b/feincms/templates/admin/feincms/page/page/item_editor.html index b9971c81a..67cb03f22 100644 --- a/feincms/templates/admin/feincms/page/page/item_editor.html +++ b/feincms/templates/admin/feincms/page/page/item_editor.html @@ -5,9 +5,6 @@ {% block object-tools %} {{ block.super }}
    - {% if original.is_active and FEINCMS_FRONTEND_EDITING %} -
  • {% trans "Edit on site" %}
  • - {% endif %} {% if not original.is_active %} {% url "feincms_preview" original.get_absolute_url|slice:"1:-1" original.pk as preview_url %} {% if preview_url %} diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index ffdec0d24..20d25e0cf 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -8,7 +8,6 @@ from django import template from django.conf import settings -from django.template.loader import render_to_string from feincms.utils import get_singleton, get_singleton_url @@ -30,11 +29,7 @@ def _render_content(content, **kwargs): return setattr(request, 'feincms_render_level', level + 1) - if (request and request.COOKIES.get('frontend_editing', False) - and hasattr(content, 'fe_render')): - r = content.fe_render(**kwargs) - else: - r = content.render(**kwargs) + r = content.render(**kwargs) if request is not None: level = getattr(request, 'feincms_render_level', 1) @@ -61,22 +56,6 @@ def feincms_render_content(context, content, request=None): return _render_content(content, request=request, context=context) -@register.simple_tag -def feincms_frontend_editing(cms_obj, request): - """ - {% feincms_frontend_editing feincms_page request %} - """ - - if (hasattr(request, 'COOKIES') - and request.COOKIES.get('frontend_editing') == 'True'): - context = template.RequestContext(request, { - "feincms_page": cms_obj, - }) - return render_to_string('admin/feincms/fe_tools.html', context) - - return '' - - @register.assignment_tag def feincms_load_singleton(template_key, cls=None): """ diff --git a/tests/testapp/templates/base.html b/tests/testapp/templates/base.html index 99e20fdc6..b26a00a98 100644 --- a/tests/testapp/templates/base.html +++ b/tests/testapp/templates/base.html @@ -32,8 +32,6 @@

    Sidebar content

    {% block sidebar %}{% feincms_render_region feincms_page "sidebar" request %}{% endblock %} - {% feincms_frontend_editing feincms_page request %} - {% get_fragment request "something" %} diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index e1fb61baa..3308db3a2 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -34,11 +34,9 @@ from feincms.context_processors import add_page_if_missing from feincms.models import ContentProxy from feincms.module.medialibrary.models import Category, MediaFile -from feincms.module.page import processors from feincms.module.page.extensions.navigation import PagePretender from feincms.module.page.models import Page from feincms.module.page.templatetags import feincms_page_tags -from feincms.templatetags import feincms_tags from feincms.translations import short_language_code from .test_stuff import Empty @@ -653,79 +651,6 @@ def test_14_richtext(self): obj.text = 'Something' self.assertTrue(isinstance(obj.render(), SafeData)) - def test_15_frontend_editing(self): - self.create_default_page_set() - page = Page.objects.get(pk=1) - self.login() - self.create_page_through_admincontent(page) - - # this should return a 404 - self.is_published('/admin/page/page/10|rawcontent|1/', should_be=False) - self.is_published('/admin/page/page/1|rawcontent|10/', should_be=False) - - self.assertEqual( - self.client.get('/admin/page/page/1|rawcontent|1/').status_code, - 200) - self.assertEqual(self.client.post('/admin/page/page/1|rawcontent|1/', { - 'rawcontent-text': 'blablabla', - }).status_code, 200) - - self.assertEqual(page.content.main[0].render(), 'blablabla') - self.assertEqual(feincms_tags.feincms_frontend_editing(page, {}), '') - - request = Empty() - request.COOKIES = {'frontend_editing': "True"} - - self.assertIn( - 'class="fe_box"', page.content.main[0].fe_render(request=request)) - - def test_15_b_client_frontend_editing(self): - self.create_default_page_set() - page = Page.objects.get(pk=1) - self.login() - self.create_page_through_admincontent(page) - - page.active = True - page.template_key = 'theother' - page.save() - - # FEINCMS_FRONTEND_EDITING is False by default - response = self.client.get( - page.get_absolute_url() + '?frontend_editing=1', - follow=True) - self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) - self.assertNotIn('frontend_editing', self.client.cookies) - - # manually register request processor - # override_settings(FEINCMS_FRONTEND_EDITING=True) wont work here - Page.register_request_processor( - processors.frontendediting_request_processor, - key='frontend_editing') - response = self.client.get( - page.get_absolute_url() + '?frontend_editing=1', - follow=True) - self.assertRedirects(response, page.get_absolute_url()) - self.assertIn('class="fe_box"', response.content.decode('utf-8')) - self.assertIn('frontend_editing', self.client.cookies) - - # turn off edit on site - response = self.client.get( - page.get_absolute_url() + '?frontend_editing=0', - follow=True) - self.assertRedirects(response, page.get_absolute_url()) - self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) - - # anonymous user cannot front edit - self.client.logout() - response = self.client.get( - page.get_absolute_url() + '?frontend_editing=1', - follow=True) - self.assertRedirects(response, page.get_absolute_url()) - self.assertNotIn('class="fe_box"', response.content.decode('utf-8')) - - # cleanup request processor - del Page.request_processors['frontend_editing'] - def test_17_page_template_tags(self): self.create_default_page_set() From ead3c0209fab20e341d0f7ddc865bf0991fe248d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 10 Oct 2014 16:16:47 +0200 Subject: [PATCH 1088/1590] Remove our home-grown schema checking support, you should really really use a real migration framework instead --- docs/settings.rst | 4 --- feincms/default_settings.py | 9 ----- feincms/management/checker.py | 66 ----------------------------------- feincms/module/blog/models.py | 9 ----- feincms/module/page/models.py | 9 +---- 5 files changed, 1 insertion(+), 96 deletions(-) delete mode 100644 feincms/management/checker.py diff --git a/docs/settings.rst b/docs/settings.rst index 05ab0b117..09cbda591 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -141,7 +141,3 @@ Various settings ``FEINCMS_THUMBNAIL_DIR``: Defaults to ``_thumbs/``. Defines a prefix for media file thumbnails. This allows you to easily remove all thumbnails without fear of removing files belonging to image and file fields. - -``FEINCMS_CHECK_DATABASE_SCHEMA``: Defaults to ``False``. Run the home-grown -schema checker on the page module. Should not be used anymore, use South or -Django 1.7's own migrations support. diff --git a/feincms/default_settings.py b/feincms/default_settings.py index e24d98fac..455c4ec22 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -95,15 +95,6 @@ 'FEINCMS_DEFAULT_PAGE_MODEL', 'page.Page') -# ------------------------------------------------------------------------ -# Various settings - -#: Run the weak replacement for a real database migration solution? -FEINCMS_CHECK_DATABASE_SCHEMA = getattr( - settings, - 'FEINCMS_CHECK_DATABASE_SCHEMA', - False) - # ------------------------------------------------------------------------ #: Allow random gunk after a valid page? FEINCMS_ALLOW_EXTRA_PATH = getattr( diff --git a/feincms/management/checker.py b/feincms/management/checker.py deleted file mode 100644 index 8c157e284..000000000 --- a/feincms/management/checker.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import absolute_import, print_function, unicode_literals - -from django.core.management.color import color_style -from django.db import connection - - -def check_database_schema(cls, model_name): - """ - Returns a function which inspects the database table of the passed class. - It checks whether all fields in the model are available on the database - too. This is especially helpful for models with an extension mechanism, - where the extension might be activated after syncdb has been run for the - first time. - - Please note that you have to connect the return value using strong - references. Here's an example how to do this:: - - signals.post_syncdb.connect( - check_database_schema(Page, __name__), weak=False) - - (Yes, this is a weak attempt at a substitute for South until we find - a way to make South work with FeinCMS' dynamic model creation.) - """ - - def _fn(sender, **kwargs): - if sender.__name__ != model_name: - return - - cursor = connection.cursor() - - existing_columns = [ - row[0] - for row in connection.introspection.get_table_description( - cursor, cls._meta.db_table) - ] - - missing_columns = [] - - for field in cls._meta.fields: - if field.column not in existing_columns: - missing_columns.append(field) - - if not missing_columns: - return - - style = color_style() - - print(style.ERROR( - 'The following columns seem to be missing in the database table' - ' %s:' % cls._meta.db_table)) - - for field in missing_columns: - print('%s:%s%s' % ( - style.SQL_KEYWORD(field.column), - ' ' * (25 - len(field.column)), - '%s.%s' % ( - field.__class__.__module__, field.__class__.__name__), - )) - - print(style.NOTICE( - '\nPlease consult the output of `python manage.py sql %s` to' - ' find out what the correct column types are. (Or use south,' - ' which is what you should be doing anyway.)\n' % ( - cls._meta.app_label))) - - return _fn diff --git a/feincms/module/blog/models.py b/feincms/module/blog/models.py index 7367c00b3..6b255cbc3 100644 --- a/feincms/module/blog/models.py +++ b/feincms/module/blog/models.py @@ -8,14 +8,11 @@ from __future__ import absolute_import, unicode_literals from django.db import models -from django.db.models import signals from django.utils import timezone from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ -from feincms import settings from feincms.admin import item_editor -from feincms.management.checker import check_database_schema from feincms.models import Base @@ -64,12 +61,6 @@ def get_absolute_url(self): return ('blog_entry_detail', (self.id,), {}) -if settings.FEINCMS_CHECK_DATABASE_SCHEMA: - signals.post_syncdb.connect( - check_database_schema(Entry, __name__), - weak=False) - - class EntryAdmin(item_editor.ItemEditor): date_hierarchy = 'published_on' list_display = ['__str__', 'published', 'published_on'] diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 029e1581b..aefa10ebb 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -10,7 +10,7 @@ from django.core.exceptions import PermissionDenied from django.conf import settings as django_settings from django.db import models -from django.db.models import Q, signals +from django.db.models import Q from django.http import Http404 from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ @@ -19,7 +19,6 @@ from feincms import settings from feincms._internal import get_model -from feincms.management.checker import check_database_schema from feincms.models import create_base_model from feincms.module.mixins import ContentModelMixin from feincms.module.page import processors @@ -425,10 +424,4 @@ class Meta: Page.register_default_processors() -if settings.FEINCMS_CHECK_DATABASE_SCHEMA: - signals.post_syncdb.connect( - check_database_schema(Page, __name__), - weak=False) - -# ------------------------------------------------------------------------ # ------------------------------------------------------------------------ From 885a4bd2195d55f651898bc9936d679f9ba8b648 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 20 Oct 2014 11:07:21 +0200 Subject: [PATCH 1089/1590] Deprecate Page.cache_key --- docs/deprecation.rst | 4 ++++ docs/releases/1.11.rst | 4 ++++ feincms/module/page/models.py | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index 94c4b47c5..7b82e7f9f 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -116,3 +116,7 @@ No deprecations. * The automatic discovery of subclasses of ``NavigationExtension`` has been replaced with an explicit mechanism of defining navigation extensions. + +* ``Page.cache_key`` has never been used by FeinCMS itself and will therefore + be removed in a future release. Comparable functionality has been available + for a long time with ``Page.path_to_cache_key``. diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst index 9545ec417..0b294e4c4 100644 --- a/docs/releases/1.11.rst +++ b/docs/releases/1.11.rst @@ -94,6 +94,10 @@ New deprecations * The automatic discovery of subclasses of ``NavigationExtension`` has been replaced with an explicit mechanism of defining navigation extensions. +* ``Page.cache_key`` has never been used by FeinCMS itself and will therefore + be removed in a future release. Comparable functionality has been available + for a long time with ``Page.path_to_cache_key``. + Notable features and improvements ================================= diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index aefa10ebb..9e1bf94d9 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, unicode_literals import re +import warnings from django.core.cache import cache as django_cache from django.core.exceptions import PermissionDenied @@ -347,6 +348,11 @@ def cache_key(self): This function is here purely for your convenience. FeinCMS itself does not use it in any way. """ + warnings.warn( + 'Page.cache_key has never been used and has therefore been' + ' deprecated and will be removed in a future release. Have a' + ' look at Page.path_to_cache_key if you require comparable' + ' functionality.', DeprecationWarning, stacklevel=2) return '-'.join(str(fn(self)) for fn in self.cache_key_components) def etag(self, request): From bb7208ad7b3a0a45a2a90155b53c50213f1c426e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 10 Mar 2015 14:04:36 +0100 Subject: [PATCH 1090/1590] Avoid an import error --- feincms/admin/item_editor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index d1bd02561..f45e7abbb 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -10,7 +10,10 @@ from django import forms from django.contrib.admin.options import InlineModelAdmin -from django.contrib.admin.utils import unquote +try: + from django.contrib.admin.utils import unquote +except ImportError: # Django 1.6 + from django.contrib.admin.util import unquote from django.contrib.auth import get_permission_codename from django.http import Http404 From 8b8179fa619e0fed26417e600c61c4edb07bb077 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 11 Mar 2015 11:16:19 +0100 Subject: [PATCH 1091/1590] Note Page.cache_key deprecation. --- docs/advanced/caching.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/advanced/caching.rst b/docs/advanced/caching.rst index 80229319a..9c6b67df2 100644 --- a/docs/advanced/caching.rst +++ b/docs/advanced/caching.rst @@ -31,7 +31,8 @@ of helper methods and variables, ready to be used in your templates. Here's an (incomplete) list of variables to use in {% cache %} blocks [#djangocache]_: - * feincms_page.cache_key -- a string describing the current page. + * feincms_page.cache_key -- DEPRECATED as of FeinCMS 1.11. + A string describing the current page. Depending on the extensions loaded, this varies with the page, the page's modification date, its language, etc. This is always a safe bet to use on page specific fragments. From 7b0227cf247ea081f8b27cfb688fe0219a998e89 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 30 Mar 2015 13:00:15 +0200 Subject: [PATCH 1092/1590] Work around #571 by wrapping the template loader instanciation in a try/except. The exception only occurs on syncdb time, I guess some initialisation order has been changed in Django itself. Of course, this also swallows legitimate exceptions here, but you can't have it all... --- feincms/content/template/models.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index d04080e5b..0ef4f9764 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -54,18 +54,29 @@ class Meta: verbose_name_plural = _('template contents') @classmethod - def initialize_type(cls, TEMPLATE_LOADERS=DEFAULT_TEMPLATE_LOADERS): - cls.template_loaders = [ - find_template_loader(loader) - for loader in TEMPLATE_LOADERS if loader] + def initialize_type(cls, TEMPLATE_LOADERS=DEFAULT_TEMPLATE_LOADERS, + TEMPLATE_PATH='content/template'): + cls.template_path = TEMPLATE_PATH + template_loaders = [] + for loader in TEMPLATE_LOADERS: + if loader: + # With Django 1.6 find_template_loader blows up during + # syncdb, probably because component initialization order + # has changed. Work around by ignoring exceptions here, + # but of course, this will also swallow legitimate + # exceptions. Tough luck :-( + try: + template_loaders.append(find_template_loader(loader)) + except Exception: + pass cls.add_to_class('filename', models.CharField( _('template'), max_length=100, - choices=TemplateChoices(cls.template_loaders))) + choices=TemplateChoices(template_loaders))) def render(self, **kwargs): context = kwargs.pop('context', None) - name = 'content/template/%s' % self.filename + name = os.path.join(self.template_path, self.filename) for loader in self.template_loaders: try: From d6b96e0123c2ba0f9a5c86828ed247110df6d2e3 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 1 Apr 2015 15:48:19 +0200 Subject: [PATCH 1093/1590] Fix oversight in previous --- feincms/content/template/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 0ef4f9764..11f5f28eb 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -53,11 +53,12 @@ class Meta: verbose_name = _('template content') verbose_name_plural = _('template contents') + template_loaders = [] + @classmethod def initialize_type(cls, TEMPLATE_LOADERS=DEFAULT_TEMPLATE_LOADERS, TEMPLATE_PATH='content/template'): cls.template_path = TEMPLATE_PATH - template_loaders = [] for loader in TEMPLATE_LOADERS: if loader: # With Django 1.6 find_template_loader blows up during @@ -66,13 +67,13 @@ def initialize_type(cls, TEMPLATE_LOADERS=DEFAULT_TEMPLATE_LOADERS, # but of course, this will also swallow legitimate # exceptions. Tough luck :-( try: - template_loaders.append(find_template_loader(loader)) + cls.template_loaders.append(find_template_loader(loader)) except Exception: pass cls.add_to_class('filename', models.CharField( _('template'), max_length=100, - choices=TemplateChoices(template_loaders))) + choices=TemplateChoices(cls.template_loaders))) def render(self, **kwargs): context = kwargs.pop('context', None) From f31d6e858be25f499053f8a2836e6d0be34b1349 Mon Sep 17 00:00:00 2001 From: Peter Schmidt Date: Thu, 9 Apr 2015 18:34:41 +1000 Subject: [PATCH 1094/1590] Add Django 1.8 to Travis, can figure out how to exclude specific versions later. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a257debc6..6b98fa236 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ python: env: - DJANGO_REQUIREMENT="Django>=1.6,<1.7" - DJANGO_REQUIREMENT="Django>=1.7,<1.8" + - DJANGO_REQUIREMENT="Django>=1.8,<1.9" matrix: exclude: - python: "2.6" From 66a4cb043fa9a25f37ea3f73cb20bd7a27de1fd7 Mon Sep 17 00:00:00 2001 From: Peter Schmidt Date: Thu, 9 Apr 2015 18:35:51 +1000 Subject: [PATCH 1095/1590] Update to Django 1.8 final as it has been released. https://docs.djangoproject.com/en/1.8/releases/1.8/ --- tests/tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tox.ini b/tests/tox.ini index 0d9a8d2ca..35f98b94d 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -14,7 +14,7 @@ setenv = deps = django16: Django>=1.6,<1.7 django17: Django>=1.7,<1.8 - django18: Django>=1.8b1,<1.9 + django18: Django>=1.8,<1.9 feedparser==5.1.3 Pillow==2.4.0 pytz==2014.10 From f9992f1a885c23c081791d30277d9a018011f647 Mon Sep 17 00:00:00 2001 From: Peter Schmidt Date: Thu, 9 Apr 2015 18:40:38 +1000 Subject: [PATCH 1096/1590] Update to django-mptt==0.7.1 as it's the latest and should be supported. Notes for anyone else who understands what's going on under the hood: http://django-mptt.github.io/django-mptt/upgrade.html --- setup.py | 2 +- tests/tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index e2befcb11..7de2162a6 100755 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ def read(filename): }, install_requires=[ 'Django>=1.6', - 'django-mptt>=0.6.0', + 'django-mptt>=0.7.1', 'Pillow>=2.0.0', 'feedparser>=5.0.0', 'pytz>=2014.10', diff --git a/tests/tox.ini b/tests/tox.ini index 35f98b94d..86eaabc66 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -21,6 +21,6 @@ deps = lxml==3.2.3 {py26,py27,py32,py33,py34}-django16: django-mptt==0.6.0 {py27,py32,py33,py34}-django17: django-mptt==0.6.1 - {py27,py34}-django18: --editable=git+git://github.com/django-mptt/django-mptt.git#egg=django-mptt-dev + {py27,py34}-django18: django-mptt==0.7.1 {py26,py27}-django{16,17,18}: BeautifulSoup==3.2.1 {py32,py33,py34}-django{16,17,18}: beautifulsoup4==4.3.1 From 3c0f72b1385e366cb06adf54bcec7f5ce92dc652 Mon Sep 17 00:00:00 2001 From: Simon Baechler Date: Thu, 9 Apr 2015 11:56:18 +0200 Subject: [PATCH 1097/1590] mention link to compatibility matrix mention link to compatibility matrix --- docs/faq.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/faq.rst b/docs/faq.rst index d804a4ab1..f019067ab 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -48,3 +48,10 @@ You can either remove the line ``Page.register_extensions(...)`` from your code or drop the page_page table and re-run ``syncdb``. If you want to keep the pages you've already created, you need to figure out the correct ALTER TABLE statements for your database yourself. + + + +Is FeinCMS version X compatible with Django version Y? +====================================================== + +Check out the compatibility matrix `here `_. From c3258ef1f1094bd69b4322186d1be971dc0c6706 Mon Sep 17 00:00:00 2001 From: Emmanuelle Delescolle Date: Thu, 9 Apr 2015 12:55:10 +0200 Subject: [PATCH 1098/1590] Django 1.8 Field.related new api compatibility --- feincms/admin/filters.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index 8e239d48a..2f8f9c380 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -11,6 +11,7 @@ from django.utils.encoding import smart_text from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ +from django import VERSION as DJANGO_VERSION from feincms.utils import shorten_string @@ -72,11 +73,18 @@ def __init__(self, f, request, params, model, model_admin, f, request, params, model, model_admin, field_path) # Restrict results to categories which are actually in use: + if DJANGO_VERSION < (1,8): + related_model = f.related.parent_model + related_name = f.related.var_name + else: + related_model = f.related_model + related_name = f.related.name + self.lookup_choices = [( i.pk, six.text_type(i)) - for i in f.related.parent_model.objects.exclude( - **{f.related.var_name: None}) + for i in related_model.objects.exclude( + **{related_name: None}) ] self.lookup_choices.sort(key=lambda i: i[1]) From 49e1091e94648f28c0a548cf007be6cda4754121 Mon Sep 17 00:00:00 2001 From: Emmanuelle Delescolle Date: Thu, 9 Apr 2015 13:07:20 +0200 Subject: [PATCH 1099/1590] removed Python 3.2/Django 1.7 test as discussed on https://github.com/feincms/feincms/issues/574 --- tests/tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tox.ini b/tests/tox.ini index 86eaabc66..2b7ced15e 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -3,7 +3,7 @@ setupdir = .. distribute = False envlist = {py26,py27,py32,py33,py34}-django16, - {py27,py32,py33,py34}-django17, + {py27,py33,py34}-django17, {py27,py34}-django18, [testenv] From 6c5c7a37a19413ceca52a1df0910af206411002b Mon Sep 17 00:00:00 2001 From: Emmanuelle Delescolle Date: Thu, 9 Apr 2015 13:17:41 +0200 Subject: [PATCH 1100/1590] updated .travis.yml to remove Python 2.6 tests for Django 1.8 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 6b98fa236..67e497146 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,8 @@ matrix: exclude: - python: "2.6" env: DJANGO_REQUIREMENT="Django>=1.7,<1.8" + - python: "2.6" + env: DJANGO_REQUIREMENT="Django>=1.8,<1.9" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q $DJANGO_REQUIREMENT django-mptt Pillow feedparser flake8 --use-mirrors From c2ba86e1612706e68d027b2a80d8742ba658dbd2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 16 Apr 2015 09:37:42 +0200 Subject: [PATCH 1101/1590] Fix #564: Document how to do migrations in Django 1.7+ --- docs/migrations.rst | 57 +++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/docs/migrations.rst b/docs/migrations.rst index bd6de9905..60332c776 100644 --- a/docs/migrations.rst +++ b/docs/migrations.rst @@ -1,23 +1,45 @@ .. _migrations: -================================================= -Database migration support for FeinCMS with South -================================================= +====================================== +Database migration support for FeinCMS +====================================== -If you don't know what South_ is you should probably go and read about -it right now! -.. _South: http://south.aeracode.org/ +FeinCMS itself does not come with any migrations. It does not have to: Its +core models haven't changed for several versions now. This does not mean +migrations aren't supported. You are free to use either Django's builtin +migrations support, or also South if you're stuck with Django versions older +than 1.6. +Django's builtin migrations +=========================== + +* Create a new folder in your app with an empty ``__init__.py`` inside. +* Add the following configuration to your ``settings.py``:: + + MIGRATION_MODULES = { + 'page': 'yourapp.migrate.page', + 'medialibrary': 'yourapp.migrate.medialibrary', + } + +.. warning:: + + You **must not** use ``migrations`` as folder name for the FeinCMS + migrations, otherwise Django and/or South **will** get confused. -FeinCMS itself does not come with any migrations. It does not have to: Its -core models haven't changed for several versions now. This does not mean South -isn't supported! You are free to use South to manage FeinCMS' models which -is a very useful technique especially if you are using :ref:`page-extensions`. -The following steps should be sufficient to get up and running with South +For those still using South +=========================== + +If you don't know what South_ is you should probably go and read about +it right now! + + +The following steps should be sufficient to get up and running with South_ in your project: +.. _South: http://south.aeracode.org/ + * Put a copy of South somewhere on your ``PYTHONPATH``, with ``pip``, ``hg`` or whatever pleases you most. * Add ``'south'`` to ``INSTALLED_APPS``. @@ -27,14 +49,9 @@ in your project: SOUTH_MIGRATION_MODULES = { 'page': 'yourapp.migrate.page', - 'medialibrary': 'yourapp.migrate.medialibrary', # if you are using the medialibrary - # which comes with FeinCMS - } + 'medialibrary': 'yourapp.migrate.medialibrary', + } -* Run ``./manage.py convert_to_south page`` and ``./manage.py convert_to_south medialibrary`` +* Run ``./manage.py convert_to_south page`` and + ``./manage.py convert_to_south medialibrary`` * That's it! - -.. warning:: - - You **must not** use ``migrations`` as folder name for the FeinCMS - migrations, otherwise South **will** get confused. From 199b4ec551452124c2ed209d6cdfe9d708b18a6d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 16 Apr 2015 09:48:57 +0200 Subject: [PATCH 1102/1590] Fix a few flake8 warnings --- feincms/__init__.py | 14 +++++++------- feincms/module/page/processors.py | 5 ++++- feincms/views/cbv/views.py | 22 +++++++++++++++------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 63d0b933c..1c38b2a02 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -80,14 +80,14 @@ def ensure_completely_loaded(force=False): # http://goo.gl/XNI2qz model._meta._fill_fields_cache() - # Calls to get_models(...) are cached by the arguments used in the call. - # This cache is normally cleared in loading.register_models(), but we - # invalidate the get_models() cache, by calling get_models - # above before all apps have loaded. (Django's load_app() doesn't clear the + # Calls to get_models(...) are cached by the arguments used in the + # call. This cache is normally cleared in loading.register_models(), + # but we invalidate the get_models() cache, by calling get_models above + # before all apps have loaded. (Django's load_app() doesn't clear the # get_models cache as it perhaps should). So instead we clear the - # get_models cache again here. If we don't do this, Django 1.5 chokes on - # a model validation error (Django 1.4 doesn't exhibit this problem). - # See Issue #323 on github. + # get_models cache again here. If we don't do this, Django 1.5 chokes + # on a model validation error (Django 1.4 doesn't exhibit this + # problem). See Issue #323 on github. if hasattr(apps, 'cache'): try: apps.cache.get_models.cache_clear() # Django 1.7+ diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 6932b0fca..86daa8807 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -7,8 +7,10 @@ from django.conf import settings as django_settings from django.http import Http404, HttpResponseRedirect + logger = logging.getLogger(__name__) + def redirect_request_processor(page, request): """ Returns a ``HttpResponseRedirect`` instance if the current page says @@ -19,7 +21,8 @@ def redirect_request_processor(page, request): extra_path = request._feincms_extra_context.get('extra_path', '/') if extra_path == '/': return HttpResponseRedirect(target) - logger.debug("Page redirect on '%s' not taken because extra path '%s' present", + logger.debug( + "Page redirect on '%s' not taken because extra path '%s' present", page.get_absolute_url(), extra_path) raise Http404() diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 2bab96c5c..5b1e74153 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -9,8 +9,10 @@ from feincms._internal import get_model from feincms.module.mixins import ContentView + logger = logging.getLogger(__name__) + class Handler(ContentView): page_model_path = None context_object_name = 'feincms_page' @@ -32,21 +34,27 @@ def dispatch(self, request, *args, **kwargs): return super(Handler, self).dispatch(request, *args, **kwargs) except Http404 as e: if settings.FEINCMS_CMS_404_PAGE is not None: - logger.info("Http404 raised for '%s', attempting redirect to FEINCMS_CMS_404_PAGE", args[0]) + logger.info( + "Http404 raised for '%s', attempting redirect to" + " FEINCMS_CMS_404_PAGE", args[0]) try: - # Fudge environment so that we end up resolving the right page. - # Note: request.path is used by the page redirect processor to - # determine if the redirect can be taken, must be == to page url + # Fudge environment so that we end up resolving the right + # page. + # Note: request.path is used by the page redirect processor + # to determine if the redirect can be taken, must be == to + # page url request.path = settings.FEINCMS_CMS_404_PAGE response = super(Handler, self).dispatch( request, settings.FEINCMS_CMS_404_PAGE, **kwargs) - # Only set status if we actually have a page. If we get - # for example a redirect, overwriting would yield a blank page + # Only set status if we actually have a page. If we get for + # example a redirect, overwriting would yield a blank page if response.status_code == 200: response.status_code = 404 return response except Http404: - logger.error("Http404 raised while resolving FEINCMS_CMS_404_PAGE=%s", + logger.error( + "Http404 raised while resolving" + " FEINCMS_CMS_404_PAGE=%s", settings.FEINCMS_CMS_404_PAGE) raise e else: From 5de7e318a214aab5dfe86c17faa7a0ecc9f036cb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 16 Apr 2015 10:46:14 +0200 Subject: [PATCH 1103/1590] Update the release notes --- docs/releases/1.11.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst index 0b294e4c4..14b0ec865 100644 --- a/docs/releases/1.11.rst +++ b/docs/releases/1.11.rst @@ -110,6 +110,15 @@ Notable features and improvements * Support for importing PIL as `import Image` has been removed. +* The builtin and mostly broken frontend editing support has been removed. This + is not a decision against frontend editing / on site editing in general, it + is more about creating a space for new ideas and new implementations. + +* The home-grown schema checking support has been removed. Real migrations + should be used instead. + +* We are logging more stuff. + Bugfixes ======== From ff9a58c4a7ab7b5930aa700b4f4f3659fb191b38 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 16 Apr 2015 10:46:28 +0200 Subject: [PATCH 1104/1590] AUTHORS update --- AUTHORS | 105 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6319e6301..2deabd630 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,92 +6,101 @@ The authors of FeinCMS are: * Simon Meers * Bojan Mihelac * Simon Bächler -* Stephan Jaekel * Bjorn Post +* Stephan Jaekel * Julien Phalip * Daniel Renz * Stefan Reinhard -* Matt Dawson * Simon Schürpf +* Matt Dawson * Skylar Saveland +* Peter Schmidt * Marc Egli * Psyton * Simon Schmid * Greg Turner * Charlie Denton -* Maarten van Gompel (proycon) * Bjarni Thorisson * Greg Taylor -* Jonas +* Maarten van Gompel (proycon) * Urs Breton +* Jonas * Antoni Aloy * Julian Bez * Afonso Fernández Nogueira -* Marc Tamlyn -* Martin Mahner -* Max Peterson -* Nico Echaniz +* Vítor Figueiró * Sander van Leeuwen +* Martin Mahner * Toby White -* Vítor Figueiró -* Andrew D. Ball +* Marc Tamlyn +* Nico Echaniz +* Max Peterson +* adsworth +* Brian Macdonald +* Gabriel Kovacs * Maarten Draijer +* Andrew D. Ball +* Emmanuelle Delescolle * Torkn -* Gabriel Kovacs * Eric Delord -* adsworth -* Brian Macdonald -* Vaclav Klecanda -* Denis Popov * tayg -* Wil Tan -* Fabian Vogler +* Cellarosi Marco +* Denis Popov * Fabian Germann +* Fabian Vogler * Håvard Grimelid +* Maciek Szczesniak * Marco Fucci -* Raphael Jasjukaitis -* Cellarosi Marco -* Richard A * Michael Bashkirov * Mikhail Korobov -* Maciek Szczesniak -* Rico Moorman +* Perry Roper +* Raphael Jasjukaitis +* Richard A +* Vaclav Klecanda +* Wil Tan +* Matthias K +* Jimmy Ye +* Alex Kamedov +* antiflu +* Mikkel Hoegh +* Jay Yu +* Olekasnadr Gula +* Paul Garner +* feczo +* Harro van der Klauw +* Piet Delport +* Gwildor Sok +* ilmarsm +* Riccardo Coroneo * niklaushug +* Richard Bolt +* Rico Moorman +* Giorgos Logiotatidis * Sebastian Hillig * Silvan Spross +* George Karpenkov +* Domas Lapinskas +* Denis Martinez +* David Evans +* Darryl Woods +* Daniele Procida * Artur Barseghyan -* Anshuman Bhaduri -* Andrin Heusser -* Andrey Popelo -* Andi Albrecht -* Alex Kamedov * Sumit Datta * Sun Liwen * Tobias Haffner +* Anshuman Bhaduri +* Andrin Heusser +* Andrey Popelo * svleeuwen -* Alen Mujezinovic * Valtron -* George Karpenkov -* Harro van der Klauw -* Jimmy Ye -* Jay Yu -* Jonas Svensson -* Domas Lapinskas -* Laurent Paoletti -* Livio Lunin -* Denis Martinez -* David Evans +* Andi Albrecht +* Alen Mujezinovic * Wim Feijen * Marco Cellarosi -* Mark Renton -* Darryl Woods * Wouter van der Graaf +* Mark Renton +* Livio Lunin +* Laurent Paoletti * Mason Hugus -* Daniele Procida -* Mikkel Hoegh -* ilmarsm -* Olekasnadr Gula -* Paul Garner -* Piet Delport -* Riccardo Coroneo -* Richard Bolt +* Kevin Etienne +* Jonas Svensson From 29b26cd025e3fedca5316d99cb33fdadb1590f14 Mon Sep 17 00:00:00 2001 From: Fabian Germann Date: Thu, 16 Apr 2015 12:16:09 +0200 Subject: [PATCH 1105/1590] When adding the format_tags option ordering is crucial. Add commented example to simplify configuration --- feincms/templates/admin/content/richtext/init_ckeditor.html | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/templates/admin/content/richtext/init_ckeditor.html b/feincms/templates/admin/content/richtext/init_ckeditor.html index 1c30cc2b9..b29b73b5f 100644 --- a/feincms/templates/admin/content/richtext/init_ckeditor.html +++ b/feincms/templates/admin/content/richtext/init_ckeditor.html @@ -9,6 +9,7 @@ {% block config %} CKEDITOR.config.width = '787'; CKEDITOR.config.height= '300'; + // CKEDITOR.config.format_tags = 'p;h1;h2;h3;h4;pre'; CKEDITOR.config.toolbar = [ {% block toolbar %}['Maximize','-','Format','-','Bold','Italic','Underline','Strike','-','Subscript','Superscript','-','NumberedList','BulletedList','-','Anchor', 'Link','Unlink','-','Source']{% endblock %} ]; From 09ba4c28276b66afba3fc085e7041db4953c7b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20B=C3=BCschlen?= Date: Thu, 16 Apr 2015 14:09:15 +0200 Subject: [PATCH 1106/1590] Flatten the CSS --- feincms/static/feincms/item_editor.css | 111 +++++++++++++++---------- feincms/static/feincms/tree_editor.css | 48 ++++++----- 2 files changed, 97 insertions(+), 62 deletions(-) diff --git a/feincms/static/feincms/item_editor.css b/feincms/static/feincms/item_editor.css index 461f10b55..cfc6e00a4 100644 --- a/feincms/static/feincms/item_editor.css +++ b/feincms/static/feincms/item_editor.css @@ -1,44 +1,36 @@ .navi_tab { float:left; - padding: 5px 14px 5px 12px; + padding: 8px 10px; cursor:pointer; - border: 1px solid #ccc; - border-bottom:none; - min-width:100px; margin-top:3px; - /* height:13px; */ font-weight: bold; - font-size: 12px; - background-image:none; - color: #333333; - background: #E1E1E1 url(img/nav-bg.gif) top repeat-x; + font-size: 11px; + color: #666; + background: #f6f6f6; + border: 1px solid #eee; + text-transform: uppercase; } .tab_active { - margin-top: 0; - padding-top: 6px; - padding-bottom: 7px; - background: #7BA0C6 url('img/default-bg.gif') top repeat-x; + background: #79aec8; color: white; + border-color: #79aec8; } #main { clear:both; padding: 10px 10px 10px 10px; - border: 1px solid #ccc; + border: 1px solid #eee; margin: 0 0 10px 0; } + .panel { display:none; position:relative; - padding-bottom:50px; -} - -.order-machine { - margin-bottom:10px; + padding-bottom: 77px; } .order-item { - margin: 0 0 10px 0; + margin: 0; position:relative; } @@ -54,8 +46,14 @@ .order-item .collapse { cursor: pointer; - color: #444; + /*color: #444;*/ font-weight: normal; + + border-bottom: 1px solid rgba(255, 255, 255, 0.25); +} + +.order-item .collapse:hover { + opacity: 0.7; } .item-delete { @@ -65,11 +63,11 @@ } .highlight, .helper { - height: 25px; + height: 34px; margin: 0 0 10px 0; border: none; opacity: 0.3; - background: url('img/item_editor_form_title.png') no-repeat left bottom; + background: #79aec8; } .helper{ @@ -123,21 +121,43 @@ textarea { } .item-controls { - background: url('img/wrench.png') no-repeat 12px center; padding-left:27px; - height: 35px; + min-height: 56px; + background-position: 12px 45%; +} + +/* Clearfix */ +.item-control-units { + overflow: hidden; } .item-control-unit { float:left; - padding: 3px 10px 0 7px; + padding: 10px; border-left: 1px solid #eee; -} .item-control-unit:first-child { border-left: none; } + +.item-control-unit .button, +.item-controls select { + margin-left: 5px; + margin-right: 5px; +} + + +.item-control-unit .button { + padding-top: 6px; + padding-bottom: 6px; +} + + +.move-control .button { + margin-left: 10px; +} + .machine-control { height:70px; padding: 5px 10px 5px 10px; @@ -147,6 +167,15 @@ textarea { left:-11px; bottom:-30px; width: 100%; + + background: #f8f8f8; + border: 1px solid #eee; + height: 95px; +} + +.machine-control .button { + padding-top: 6px; + padding-bottom: 6px; } .control-unit { @@ -154,6 +183,9 @@ textarea { padding-left: 5px; padding-right:20px; border-left: 1px solid #eee; + + padding-bottom: 10px; + padding-top: 12px; } .control-unit:first-child { @@ -199,10 +231,8 @@ a.audiocontent:hover { background-position: -350px -70px; } } .empty-machine-msg { - margin:10px 0px 5px 300px; - font-style: italic; + margin:10px 0px 20px 20px; font-size:14px; - color:#999; } td span select { @@ -210,12 +240,6 @@ td span select { } -/* override Django admin styles */ -.order-machine fieldset.module > h2{ - padding: 4px 5px 6px 17px; - background: url(img/item_editor_form_title.png) no-repeat left bottom; -} - .change-template-button { margin-left: 7em; padding-left: 30px; @@ -223,15 +247,15 @@ td span select { /* Allow nested lists in error items */ ul.errorlist ul { - margin-left: 1em; - padding-left: 0; - list-style-type: square; + margin-left: 1em; + padding-left: 0; + list-style-type: square; } ul.errorlist li li { - /* Avoid repeating the warning image every time*/ - background-image:none; - padding: 0; + /* Avoid repeating the warning image every time*/ + background-image:none; + padding: 0; } div.order-machine div.inline-related > h3{ @@ -246,6 +270,9 @@ div.order-machine div.inline-related > h3{ /* various overrides */ #id_redirect_to { width: 20em; } /* raw_id_fields act-a-like for redirect_to */ +/* overwrite flat theme default label width because of problems with the CKEditor */ +.aligned .text label { width: auto; } + /* django suit hacks */ /*********************/ diff --git a/feincms/static/feincms/tree_editor.css b/feincms/static/feincms/tree_editor.css index fd527afa9..5debdc8f6 100644 --- a/feincms/static/feincms/tree_editor.css +++ b/feincms/static/feincms/tree_editor.css @@ -4,50 +4,58 @@ tr.cut { border: 2px dashed black; opacity: 0.5; } .title-column { width: 400px; } -table#result_list :focus { background-color: #ccddff !important; outline: 0px; } +#result_list tbody tr:focus { + background-color: #79aec8 !important; + outline: 0px; + color: #ffffff; +} +#result_list tbody tr:focus .field-indented_short_title a { + color: white; +} .drag_handle { - width: 16px; - height: 16px; - background: url(img/arrow-move.png); - display: inline-block; - vertical-align: middle; + width: 16px; + height: 16px; + background: url(img/arrow-move.png); + display: inline-block; + vertical-align: middle; } .drag_handle:hover { - cursor: move; + cursor: move; } .drag_order img { - cursor: move; + cursor: move; } table tr.dragging { - opacity: .3; + opacity: .3; } table tr.dragging td { - color: #333; + color: #333; } table tr.folded { - background: red; + background: red; } div#drag_line { - position: relative; - height: 3px; - font-size: 0px; - background-color: #800080; + position: relative; + height: 3px; + font-size: 0px; + background-color: #417690; } div#drag_line div { - position: absolute; - height: 9px; - width: 9px; - background-image: url(img/drag_order_circle.png); - margin: -3px 0 0 -9px; + position: absolute; + height: 9px; + width: 9px; + background: #417690; + margin: -3px 0 0 -9px; + border-radius: 9px; } .page_marker.children { From 702e2ed651768f58d9cda8dc62584b48daec99eb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 16 Apr 2015 15:32:50 +0200 Subject: [PATCH 1107/1590] Really small CSS fix --- feincms/static/feincms/item_editor.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.css b/feincms/static/feincms/item_editor.css index cfc6e00a4..0eff093b9 100644 --- a/feincms/static/feincms/item_editor.css +++ b/feincms/static/feincms/item_editor.css @@ -135,6 +135,7 @@ textarea { float:left; padding: 10px; border-left: 1px solid #eee; +} .item-control-unit:first-child { border-left: none; @@ -262,7 +263,7 @@ div.order-machine div.inline-related > h3{ display: none; } -.hidden-form-row{ +.hidden-form-row { display: none; } From f64d8ac1d0ed6b689ef8e18968545478ff71c8e3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 22 Apr 2015 16:00:19 +0200 Subject: [PATCH 1108/1590] Mention CSS changes in the README --- docs/releases/1.11.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst index 14b0ec865..b7b06b461 100644 --- a/docs/releases/1.11.rst +++ b/docs/releases/1.11.rst @@ -119,6 +119,10 @@ Notable features and improvements * We are logging more stuff. +* The admin CSS has been updated in preparation for Django's (hopefully!) + upcoming + `django-flat-theme `_ merge. + Bugfixes ======== From 5c855226315a7cebad00c1ecd66e21fbef6be1db Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 22 Apr 2015 16:00:55 +0200 Subject: [PATCH 1109/1590] FeinCMS v1.11 --- docs/releases/1.11.rst | 6 +++--- feincms/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/releases/1.11.rst b/docs/releases/1.11.rst index b7b06b461..9dff918cc 100644 --- a/docs/releases/1.11.rst +++ b/docs/releases/1.11.rst @@ -1,6 +1,6 @@ -===================================== -FeinCMS 1.11 release notes (upcoming) -===================================== +========================== +FeinCMS 1.11 release notes +========================== Welcome to FeinCMS 1.11! diff --git a/feincms/__init__.py b/feincms/__init__.py index 1c38b2a02..bd4ff8eaf 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 11, 0, 'pre') +VERSION = (1, 11, 0) __version__ = '.'.join(map(str, VERSION)) From 3b5f372799f228e59bf4c920a5a1bd963e6c2721 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Fri, 24 Apr 2015 10:54:40 +0200 Subject: [PATCH 1110/1590] Update jquery to 1.11.2 --- feincms/static/feincms/jquery-1.11.1.min.js | 4 ---- feincms/static/feincms/jquery-1.11.2.min.js | 4 ++++ feincms/templates/admin/feincms/load-jquery.include | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 feincms/static/feincms/jquery-1.11.1.min.js create mode 100644 feincms/static/feincms/jquery-1.11.2.min.js diff --git a/feincms/static/feincms/jquery-1.11.1.min.js b/feincms/static/feincms/jquery-1.11.1.min.js deleted file mode 100644 index ab28a2472..000000000 --- a/feincms/static/feincms/jquery-1.11.1.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
    ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; -if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
    a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:k.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m(" diff --git a/feincms/templates/content/video/youtube.html b/feincms/templates/content/video/youtube.html deleted file mode 100644 index 2b5fec51c..000000000 --- a/feincms/templates/content/video/youtube.html +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From d6fcfe6218f82f50ccafbcaae53537350baa2082 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:06:14 +0200 Subject: [PATCH 1218/1590] ckeditor: Reindent template, less global vars --- .../admin/content/richtext/init_ckeditor.html | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/feincms/templates/admin/content/richtext/init_ckeditor.html b/feincms/templates/admin/content/richtext/init_ckeditor.html index 61559e3d7..4c46b7dc6 100644 --- a/feincms/templates/admin/content/richtext/init_ckeditor.html +++ b/feincms/templates/admin/content/richtext/init_ckeditor.html @@ -6,16 +6,29 @@ From 314e33cd43b71fee921bcd4068351aead7196af8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:06:52 +0200 Subject: [PATCH 1219/1590] Move the MediaFileContent into the medialibrary app ... thereby making it even clearer that it is not the way to go anymore. --- feincms/contents.py | 66 ---------------- .../commands/medialibrary_to_filer.py | 5 +- feincms/module/medialibrary/contents.py | 75 +++++++++++++++++++ tests/testapp/models.py | 3 +- tests/testapp/tests/test_cms.py | 3 +- 5 files changed, 81 insertions(+), 71 deletions(-) create mode 100644 feincms/module/medialibrary/contents.py diff --git a/feincms/contents.py b/feincms/contents.py index 7414d797b..76f4253d9 100644 --- a/feincms/contents.py +++ b/feincms/contents.py @@ -10,72 +10,6 @@ from feincms import settings from feincms.admin.item_editor import FeinCMSInline from feincms.contrib.richtext import RichTextField -from feincms.module.medialibrary.fields import ContentWithMediaFile - - -class MediaFileContentInline(FeinCMSInline): - raw_id_fields = ('mediafile',) - radio_fields = {'type': admin.VERTICAL} - - -class MediaFileContent(ContentWithMediaFile): - """ - Rehashed, backwards-incompatible media file content which does not contain - the problems from v1 anymore. - - Create a media file content as follows:: - - from feincms.content.medialibrary.v2 import MediaFileContent - Page.create_content_type(MediaFileContent, TYPE_CHOICES=( - ('default', _('Default')), - ('lightbox', _('Lightbox')), - ('whatever', _('Whatever')), - )) - - For a media file of type 'image' and type 'lightbox', the following - templates are tried in order: - - * content/mediafile/image_lightbox.html - * content/mediafile/image.html - * content/mediafile/lightbox.html - * content/mediafile/default.html - - The context contains ``content`` and ``request`` (if available). - """ - - feincms_item_editor_inline = MediaFileContentInline - - class Meta: - abstract = True - verbose_name = _('media file') - verbose_name_plural = _('media files') - - @classmethod - def initialize_type(cls, TYPE_CHOICES=None): - if TYPE_CHOICES is None: - raise ImproperlyConfigured( - 'You have to set TYPE_CHOICES when' - ' creating a %s' % cls.__name__) - - cls.add_to_class( - 'type', - models.CharField( - _('type'), - max_length=20, - choices=TYPE_CHOICES, - default=TYPE_CHOICES[0][0], - ) - ) - - def render(self, **kwargs): - ctx = {'content': self} - ctx.update(kwargs) - return render_to_string([ - 'content/mediafile/%s_%s.html' % (self.mediafile.type, self.type), - 'content/mediafile/%s.html' % self.mediafile.type, - 'content/mediafile/%s.html' % self.type, - 'content/mediafile/default.html', - ], ctx, context_instance=kwargs.get('context')) class RawContent(models.Model): diff --git a/feincms/management/commands/medialibrary_to_filer.py b/feincms/management/commands/medialibrary_to_filer.py index 2c52c70c2..ff34c8d41 100644 --- a/feincms/management/commands/medialibrary_to_filer.py +++ b/feincms/management/commands/medialibrary_to_filer.py @@ -4,9 +4,8 @@ from django.core.management.base import NoArgsCommand from django.contrib.auth.models import User -from feincms.contents import ( - MediaFileContent, FilerFileContent, FilerImageContent, -) +from feincms.contents import FilerFileContent, FilerImageContent +from feincms.module.medialibrary.contents import MediaFileContent from feincms.module.medialibrary.models import MediaFile from feincms.module.page.models import Page diff --git a/feincms/module/medialibrary/contents.py b/feincms/module/medialibrary/contents.py new file mode 100644 index 000000000..c87cebe65 --- /dev/null +++ b/feincms/module/medialibrary/contents.py @@ -0,0 +1,75 @@ +from __future__ import unicode_literals + +from django.contrib import admin +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ + +from feincms.admin.item_editor import FeinCMSInline +from feincms.module.medialibrary.fields import ContentWithMediaFile + + +class MediaFileContentInline(FeinCMSInline): + raw_id_fields = ('mediafile',) + radio_fields = {'type': admin.VERTICAL} + + +class MediaFileContent(ContentWithMediaFile): + """ + Rehashed, backwards-incompatible media file content which does not contain + the problems from v1 anymore. + + Create a media file content as follows:: + + from feincms.content.medialibrary.v2 import MediaFileContent + Page.create_content_type(MediaFileContent, TYPE_CHOICES=( + ('default', _('Default')), + ('lightbox', _('Lightbox')), + ('whatever', _('Whatever')), + )) + + For a media file of type 'image' and type 'lightbox', the following + templates are tried in order: + + * content/mediafile/image_lightbox.html + * content/mediafile/image.html + * content/mediafile/lightbox.html + * content/mediafile/default.html + + The context contains ``content`` and ``request`` (if available). + """ + + feincms_item_editor_inline = MediaFileContentInline + + class Meta: + abstract = True + verbose_name = _('media file') + verbose_name_plural = _('media files') + + @classmethod + def initialize_type(cls, TYPE_CHOICES=None): + if TYPE_CHOICES is None: + raise ImproperlyConfigured( + 'You have to set TYPE_CHOICES when' + ' creating a %s' % cls.__name__) + + cls.add_to_class( + 'type', + models.CharField( + _('type'), + max_length=20, + choices=TYPE_CHOICES, + default=TYPE_CHOICES[0][0], + ) + ) + + def render(self, **kwargs): + ctx = {'content': self} + ctx.update(kwargs) + return render_to_string([ + 'content/mediafile/%s_%s.html' % (self.mediafile.type, self.type), + 'content/mediafile/%s.html' % self.mediafile.type, + 'content/mediafile/%s.html' % self.type, + 'content/mediafile/default.html', + ], ctx, context_instance=kwargs.get('context')) diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 59766f865..a1be16ae0 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -7,8 +7,9 @@ from django.utils.translation import ugettext_lazy as _ from feincms.apps import ApplicationContent -from feincms.contents import RawContent, MediaFileContent, TemplateContent +from feincms.contents import RawContent, TemplateContent from feincms.models import Base, create_base_model +from feincms.module.medialibrary.contents import MediaFileContent from feincms.module.page.models import Page from feincms.module.page import processors diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 305be7738..5e76d0b51 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -9,7 +9,8 @@ from django.db import models from django.test import TestCase -from feincms.contents import RawContent, RichTextContent, MediaFileContent +from feincms.contents import RawContent, RichTextContent +from feincms.module.medialibrary.contents import MediaFileContent from testapp.models import ExampleCMSBase, ExampleCMSBase2 from .test_stuff import Empty From 93e10e36b2906cba41eef782b7ed8ba3ef5ab01f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:12:00 +0200 Subject: [PATCH 1220/1590] FeinCMS 2.0a9 --- feincms/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index a075b86ed..c6a254ed9 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,8 +1,8 @@ from __future__ import absolute_import, unicode_literals -VERSION = (2, 0, 'a', 8) +VERSION = (2, 0, 'a', 9) # __version__ = '.'.join(map(str, VERSION)) -__version__ = '2.0a8' +__version__ = '2.0a9' class LazySettings(object): From 0e73afe928283c6afa65df6eaa4cc2cb386d0a57 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:28:37 +0200 Subject: [PATCH 1221/1590] Prepare queryset_transform for Django 1.9 --- feincms/utils/queryset_transform.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 51807f951..3755ab5dd 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -90,9 +90,10 @@ class TransformQuerySet(models.query.QuerySet): def __init__(self, *args, **kwargs): super(TransformQuerySet, self).__init__(*args, **kwargs) self._transform_fns = [] + self._orig_iterable_class = getattr(self, '_iterable_class', None) - def _clone(self, klass=None, setup=False, **kw): - c = super(TransformQuerySet, self)._clone(klass, setup, **kw) + def _clone(self, *args, **kwargs): + c = super(TransformQuerySet, self)._clone(*args, **kwargs) c._transform_fns = self._transform_fns[:] return c @@ -103,12 +104,18 @@ def transform(self, *fn): def iterator(self): result_iter = super(TransformQuerySet, self).iterator() - if self._transform_fns: - results = list(result_iter) - for fn in self._transform_fns: - fn(results) - return iter(results) - return result_iter + + if not self._transform_fns: + return result_iter + + if getattr(self, '_iterable_class', None) != self._orig_iterable_class: + # Do not process the result of values() and values_list() + return result_iter + + results = list(result_iter) + for fn in self._transform_fns: + fn(results) + return iter(results) if hasattr(models.Manager, 'from_queryset'): From 00e0b1eb3bbb2c4649d3bdecf0eb6bc0dd4c21a1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:38:00 +0200 Subject: [PATCH 1222/1590] The return value of feincms_render_region is safe --- feincms/templatetags/feincms_tags.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 42da0e9e3..a1820e1d1 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -8,6 +8,7 @@ from django import template from django.conf import settings +from django.utils.safestring import mark_safe from feincms.utils import get_singleton, get_singleton_url @@ -46,9 +47,9 @@ def feincms_render_region(context, feincms_object, region, request=None): if not feincms_object: return '' - return ''.join( + return mark_safe(''.join( _render_content(content, request=request, context=context) - for content in getattr(feincms_object.content, region)) + for content in getattr(feincms_object.content, region))) @register.simple_tag(takes_context=True) From d465bd46a330bf0192b9588f4ffcbb5db070f83b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:38:50 +0200 Subject: [PATCH 1223/1590] FeinCMS 2.0a10 --- feincms/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index c6a254ed9..7e7233b8c 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,8 +1,8 @@ from __future__ import absolute_import, unicode_literals -VERSION = (2, 0, 'a', 9) +VERSION = (2, 0, 'a', 10) # __version__ = '.'.join(map(str, VERSION)) -__version__ = '2.0a9' +__version__ = '2.0a10' class LazySettings(object): From 7e09d9c821d9dbd72cf60c19708f91a3248d3b95 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:48:50 +0200 Subject: [PATCH 1224/1590] This certainly works --- feincms/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index aad088e3e..3c07d91a7 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -416,7 +416,7 @@ def _template(self): (template_.key, template_.title,) for template_ in cls._feincms_templates.values() ] - field.default = field.choices[0][0] + field.default = cls.TEMPLATE_CHOICES[0][0] # Build a set of all regions used anywhere cls._feincms_all_regions = set() From e8cca4c7fb84f709f110967cfa5698b38f93224e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 10:03:41 +0200 Subject: [PATCH 1225/1590] Do not hardcode the change URL --- tests/testapp/tests/test_page.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index d9645b4f3..c4265c893 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -11,8 +11,9 @@ from django.conf import settings from django.contrib.auth.models import User, AnonymousUser from django.contrib.contenttypes.models import ContentType -from django.db import models from django.contrib.sites.models import Site +from django.core.urlresolvers import reverse +from django.db import models from django.http import Http404, HttpResponseBadRequest from django.template import TemplateDoesNotExist from django.template.defaultfilters import slugify @@ -177,10 +178,14 @@ def test_03_item_editor(self): self.login() self.assertRedirects( self.create_page_through_admin(_continue=1), - '/admin/page/page/1/') + reverse('admin:page_page_change', args=(1,))) self.assertEqual( - self.client.get('/admin/page/page/1/').status_code, 200) - self.is_published('/admin/page/page/42/', should_be=False) + self.client.get( + reverse('admin:page_page_change', args=(1,)) + ).status_code, 200) + self.is_published( + reverse('admin:page_page_change', args=(42,)), + should_be=False) def test_03_add_another(self): self.login() @@ -379,7 +384,9 @@ def create_page_through_admincontent(self, page, **kwargs): } data.update(kwargs) - return self.client.post('/admin/page/page/%s/' % page.pk, data) + return self.client.post( + reverse('admin:page_page_change', args=(page.pk,)), + data) def test_09_pagecontent(self): self.create_default_page_set() @@ -461,7 +468,7 @@ def test_10_mediafile_and_imagecontent(self): '%s-ha' % short_language_code() in mf.available_translations) # this should not raise - self.client.get('/admin/page/page/1/') + self.client.get(reverse('admin:page_page_change', args=(1,))) page.mediafilecontent_set.update(mediafile=3) # this should not raise @@ -1139,7 +1146,9 @@ def test_24_admin_redirects(self): page = Page.objects.get(pk=1) response = self.create_page_through_admincontent(page, _continue=1) - self.assertRedirects(response, '/admin/page/page/1/') + self.assertRedirects( + response, + reverse('admin:page_page_change', args=(1,))) response = self.create_page_through_admincontent(page, _addanother=1) self.assertRedirects(response, '/admin/page/page/add/') @@ -1656,5 +1665,7 @@ def test_41_templatecontent(self): # The empty form contains the template option. self.login() self.assertContains( - self.client.get('/admin/page/page/%s/' % page.id), + self.client.get( + reverse('admin:page_page_change', args=(page.id,)) + ), '') From 6ddcdc5dd30d5d1b5d23ff29a7058c1c15f799f2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 10:51:08 +0200 Subject: [PATCH 1226/1590] The prefix= argument has been removed, use semi-official API instead --- feincms/apps/reverse.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/feincms/apps/reverse.py b/feincms/apps/reverse.py index 387e025f9..26ee8cade 100644 --- a/feincms/apps/reverse.py +++ b/feincms/apps/reverse.py @@ -3,14 +3,16 @@ from functools import wraps from django.core.cache import cache -from django.core.urlresolvers import NoReverseMatch, reverse +from django.core.urlresolvers import ( + NoReverseMatch, reverse, get_script_prefix, set_script_prefix +) from django.utils.functional import lazy APP_REVERSE_CACHE_TIMEOUT = 3 -def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, +def app_reverse(viewname, urlconf=None, args=None, kwargs=None, *vargs, **vkwargs): """ Reverse URLs from application contents @@ -59,13 +61,17 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, if url_prefix: # vargs and vkwargs are used to send through additional parameters # which are uninteresting to us (such as current_app) - return reverse( - viewname, - url_prefix[0], - args=args, - kwargs=kwargs, - prefix=url_prefix[1], - *vargs, **vkwargs) + prefix = get_script_prefix() + try: + set_script_prefix(url_prefix[1]) + return reverse( + viewname, + url_prefix[0], + args=args, + kwargs=kwargs, + *vargs, **vkwargs) + finally: + set_script_prefix(prefix) raise NoReverseMatch("Unable to find ApplicationContent for %r" % urlconf) From bd34e3c00eb8edf48fe1dc34d178b95899d63885 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 10:57:14 +0200 Subject: [PATCH 1227/1590] Fix more test fails --- tests/testapp/applicationcontent_urls.py | 4 ++-- tests/testapp/tests/test_page.py | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index 197907d9f..5a1ba3cb4 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -13,7 +13,7 @@ def module_root(request): - return 'module_root' + return HttpResponse('module_root') def args_test(request, kwarg1, kwarg2): @@ -33,7 +33,7 @@ def fragment(request): def redirect(request): - return HttpResponseRedirect('../') + return HttpResponseRedirect(request.build_absolute_uri('../')) def response(request): diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index c4265c893..1c81549e2 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1217,7 +1217,7 @@ def test_25_applicationcontent(self): self.assertRedirects( self.client.get(page.get_absolute_url() + 'redirect/'), - page.get_absolute_url()) + 'http://testserver' + page.get_absolute_url()) self.assertEqual( app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), @@ -1263,21 +1263,23 @@ def test_25_applicationcontent(self): # Ensure ApplicationContent's admin_fields support works properly self.login() - self.assertContains( - self.client.get('/admin/page/page/%d/' % page1.id), - 'exclusive_subpages') - self.assertContains( - self.client.get('/admin/page/page/%d/' % page1.id), - 'custom_field' + response = self.client.get( + reverse('admin:page_page_change', args=(page1.id,)) ) + self.assertContains(response, 'exclusive_subpages') + self.assertContains(response, 'custom_field') + + # Check if admin_fields get populated correctly app_ct = page1.applicationcontent_set.all()[0] app_ct.parameters =\ '{"custom_field":"val42", "exclusive_subpages": false}' app_ct.save() - r = self.client.get('/admin/page/page/%d/' % page1.id) - self.assertContains(r, 'val42') + response = self.client.get( + reverse('admin:page_page_change', args=(page1.id,)) + ) + self.assertContains(response, 'val42') def test_26_page_form_initial(self): self.create_default_page_set() From eb05fe3f50406c7e202c20705cb7b64645ba4de6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 10:59:48 +0200 Subject: [PATCH 1228/1590] flake8, and run tests with Django 1.9a1 --- .travis.yml | 1 + tests/testapp/tests/test_page.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0b2f61814..2190c98c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ python: env: - DJANGO_REQUIREMENT="Django>=1.7,<1.8" - DJANGO_REQUIREMENT="Django>=1.8,<1.9" + - DJANGO_REQUIREMENT="Django==1.9a1" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q $DJANGO_REQUIREMENT django-mptt Pillow feedparser flake8 --use-mirrors diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 1c81549e2..52a9051b6 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1270,7 +1270,6 @@ def test_25_applicationcontent(self): self.assertContains(response, 'exclusive_subpages') self.assertContains(response, 'custom_field') - # Check if admin_fields get populated correctly app_ct = page1.applicationcontent_set.all()[0] app_ct.parameters =\ From 118e026faaf5f0799bcf859111293d0d639ca346 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 11:03:00 +0200 Subject: [PATCH 1229/1590] django-mptt@master --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2190c98c2..5b36a889a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,8 @@ env: - DJANGO_REQUIREMENT="Django==1.9a1" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - - pip install -q $DJANGO_REQUIREMENT django-mptt Pillow feedparser flake8 --use-mirrors +# FIXME revert to a mptt release once it supports Django 1.9 + - pip install -q $DJANGO_REQUIREMENT https://github.com/django-mptt/django-mptt/archive/master.zip Pillow feedparser flake8 --use-mirrors - python setup.py -q install # command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && flake8 ." From 2659908d044678d6cbf90492e898d1aa9e3dc462 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 11:07:50 +0200 Subject: [PATCH 1230/1590] Django 1.9 will not support Python 3.2 anymore --- .travis.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5b36a889a..71d43db96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,16 @@ python: - "3.2" - "3.4" env: - - DJANGO_REQUIREMENT="Django>=1.7,<1.8" - - DJANGO_REQUIREMENT="Django>=1.8,<1.9" - - DJANGO_REQUIREMENT="Django==1.9a1" + - REQ="Django>=1.7,<1.8 django-mptt" + - REQ="Django>=1.8,<1.9 django-mptt" + - REQ="Django==1.9a1 https://github.com/django-mptt/django-mptt/archive/master.zip" +matrix: + exclude: + - python: "3.2" + - env: REQ="Django==1.9a1 https://github.com/django-mptt/django-mptt/archive/master.zip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: -# FIXME revert to a mptt release once it supports Django 1.9 - - pip install -q $DJANGO_REQUIREMENT https://github.com/django-mptt/django-mptt/archive/master.zip Pillow feedparser flake8 --use-mirrors + - pip install $REQ Pillow feedparser flake8 - python setup.py -q install # command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && flake8 ." From 49becd5134623c9b1c7f9697fa8c8ece3e20448f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 11:08:26 +0200 Subject: [PATCH 1231/1590] Oops --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 71d43db96..07e1e01e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ env: matrix: exclude: - python: "3.2" - - env: REQ="Django==1.9a1 https://github.com/django-mptt/django-mptt/archive/master.zip" + env: REQ="Django==1.9a1 https://github.com/django-mptt/django-mptt/archive/master.zip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install $REQ Pillow feedparser flake8 From 210964f470fac36ff6a3eeb56c2c125d7dd65b60 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 10 Oct 2015 12:07:14 +0200 Subject: [PATCH 1232/1590] Almost everything in ie_compat.js is unused --- feincms/static/feincms/ie_compat.js | 98 ------------------- feincms/static/feincms/item_editor.js | 10 ++ feincms/static/feincms/tree_editor.js | 11 +++ .../templates/admin/feincms/item_editor.html | 1 - .../templates/admin/feincms/tree_editor.html | 1 - 5 files changed, 21 insertions(+), 100 deletions(-) delete mode 100644 feincms/static/feincms/ie_compat.js diff --git a/feincms/static/feincms/ie_compat.js b/feincms/static/feincms/ie_compat.js deleted file mode 100644 index f10fa4b93..000000000 --- a/feincms/static/feincms/ie_compat.js +++ /dev/null @@ -1,98 +0,0 @@ -/* Re-implement some methods IE sadly does not */ - -if(typeof(Array.prototype.indexOf) == 'undefined') { - // indexOf() function prototype for IE6/7/8 compatibility, taken from - // JavaScript Standard Library - http://www.devpro.it/JSL/ - Array.prototype.indexOf=function(elm,i){ - var j=this.length; - if(!i)i=0; - if(i>=0){while(i>> 0; - if (len === 0) { - return -1; - } - - n = len; - if (arguments.length > 1) { - n = Number(arguments[1]); - if (n != n) { - n = 0; - } - else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - - for (k = n >= 0 - ? Math.min(n, len - 1) - : len - Math.abs(n); k >= 0; k--) { - if (k in t && t[k] === searchElement) { - return k; - } - } - return -1; - }; -} diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index b034a6ab6..8f1c14720 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -1,3 +1,13 @@ +// IE<9 lacks Array.prototype.indexOf +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function(needle) { + for (i=0, l=this.length; i - {% include "admin/feincms/_messages_js.html" %} diff --git a/feincms/templates/admin/feincms/tree_editor.html b/feincms/templates/admin/feincms/tree_editor.html index e0629cb08..5d7785054 100644 --- a/feincms/templates/admin/feincms/tree_editor.html +++ b/feincms/templates/admin/feincms/tree_editor.html @@ -11,7 +11,6 @@ feincms.node_levels = {{ node_levels|default:"{}" }}; - {% endblock %} From 627b0aec6ae61d139975c334b6034376ea05d219 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 13 Oct 2015 10:59:51 +0200 Subject: [PATCH 1233/1590] Add a code of conduct --- CONTRIBUTING.rst | 19 +++++++++++++++++++ MANIFEST.in | 1 + 2 files changed, 20 insertions(+) create mode 100644 CONTRIBUTING.rst diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 000000000..ddf1d89ba --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,19 @@ +======================= +Contributing to FeinCMS +======================= + +Submission guidelines +===================== + +If you are creating a pull request, fork the repository and make any changes +in your own feature branch. + +Write and run tests. + + +Code of Conduct +=============== + +This project adheres to the +`Open Code of Conduct `_. +By participating, you are expected to honor this code. diff --git a/MANIFEST.in b/MANIFEST.in index 2b605a533..b8a1e6a53 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include AUTHORS +include CONTRIBUTING.rst include LICENSE include MANIFEST.in include README.rst From bc613a747c451feab0a708c102e63f2911163fc9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 29 Oct 2015 11:18:51 +0100 Subject: [PATCH 1234/1590] formsets, not formset --- feincms/admin/item_editor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 35315f0b7..96295ec07 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -203,9 +203,9 @@ def change_view(self, request, object_id, **kwargs): return super(ItemEditor, self).change_view( request, object_id, **kwargs) - def save_related(self, request, form, formset, change): + def save_related(self, request, form, formsets, change): super(ItemEditor, self).save_related( - request, form, formset, change) + request, form, formsets, change) itemeditor_post_save_related.send( sender=form.instance.__class__, instance=form.instance, From 30d1e263e1ac32cdd1550517de003791e533b2de Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 29 Oct 2015 11:19:03 +0100 Subject: [PATCH 1235/1590] FeinCMS 2.0a11 --- feincms/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 7e7233b8c..6b9425f80 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,8 +1,8 @@ from __future__ import absolute_import, unicode_literals -VERSION = (2, 0, 'a', 10) +VERSION = (2, 0, 'a', 11) # __version__ = '.'.join(map(str, VERSION)) -__version__ = '2.0a10' +__version__ = '2.0a11' class LazySettings(object): From 6ae651717e2f7a0c4835aa7998c29f2b0fa14afa Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 24 Nov 2015 17:10:50 +0100 Subject: [PATCH 1236/1590] When doing a lookup for a FEINCMS_CMS_404_PAGE lookup, clear out the cached page attribute on request, so we actually do a new lookup and not re-raise the 404 we just caught. See issue #575 --- feincms/views/cbv/views.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 5b1e74153..27b588bb2 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -42,8 +42,12 @@ def dispatch(self, request, *args, **kwargs): # page. # Note: request.path is used by the page redirect processor # to determine if the redirect can be taken, must be == to - # page url - request.path = settings.FEINCMS_CMS_404_PAGE + # page url. + # Also clear out the _feincms_page attribute which caches + # page lookups (and would just re-raise a 404). + request.path = request.path_info = settings.FEINCMS_CMS_404_PAGE + if hasattr(request, '_feincms_page'): + delattr(request, '_feincms_page') response = super(Handler, self).dispatch( request, settings.FEINCMS_CMS_404_PAGE, **kwargs) # Only set status if we actually have a page. If we get for From a40e6bfa0f1993a7be359006f13579bb334fe374 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 30 Nov 2015 14:13:12 +0100 Subject: [PATCH 1237/1590] Work around new warning in Django 1.8 which caused a warning for Page, MediaFile, Category, MediaFileTranslation: RemovedInDjango19Warning: Model class ... doesn't declare an explicit app_label and either isn't in an application in INSTALLED_APPS or else was imported before its application was loaded. This will no longer be supported in Django 1.9. --- feincms/module/medialibrary/models.py | 5 ++++- feincms/module/page/models.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 21d9799bf..2896b56ba 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -54,6 +54,7 @@ class Meta: ordering = ['parent__title', 'title'] verbose_name = _('category') verbose_name_plural = _('categories') + app_label = 'medialibrary' objects = CategoryManager() @@ -240,7 +241,8 @@ def delete_mediafile(self, name=None): # ------------------------------------------------------------------------ class MediaFile(MediaFileBase): - pass + class Meta: + app_label = 'medialibrary' @receiver(post_delete, sender=MediaFile) @@ -264,6 +266,7 @@ class Meta: verbose_name = _('media file translation') verbose_name_plural = _('media file translations') unique_together = ('parent', 'language_code') + app_label = 'medialibrary' def __str__(self): return self.caption diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 9e1bf94d9..ac2fa3707 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -426,6 +426,7 @@ class Meta: ordering = ['tree_id', 'lft'] verbose_name = _('page') verbose_name_plural = _('pages') + app_label = 'page' # not yet # permissions = (("edit_page", _("Can edit page metadata")),) Page.register_default_processors() From 32bbfd3add6d6ffe378fc50627769e4341f38b8e Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 30 Nov 2015 15:46:24 +0100 Subject: [PATCH 1238/1590] get_navigation_url could never have worked right: When having an internal link "page.page:13", it would return the url of the current page. Even if the comparison had been right, then the returned url would have been "page.page:13", which is totally bogus for something to put into an tag. Now tries to resolve the redirect into a real url. Also factor out a get_redirect_to_target(), so that one can get the real internal target of a page in templates too. --- feincms/module/page/models.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index ac2fa3707..0d25374c6 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -329,10 +329,9 @@ def get_navigation_url(self): Return either ``redirect_to`` if it is set, or the URL of this page. """ - # :-( maybe this could be cleaned up a bit? - if not self.redirect_to or REDIRECT_TO_RE.match(self.redirect_to): - return self._cached_url - return self.redirect_to + if self.redirect_to: + return self.get_redirect_to_target() + return self._cached_url cache_key_components = [ lambda p: getattr(django_settings, 'SITE_ID', 0), @@ -374,34 +373,45 @@ def last_modified(self, request): """ return None - def get_redirect_to_target(self, request): + def get_redirect_to_page(self): """ This might be overriden/extended by extension modules. """ if not self.redirect_to: - return '' + return None # It might be an identifier for a different object match = REDIRECT_TO_RE.match(self.redirect_to) # It's not, oh well. if not match: - return self.redirect_to + return None matches = match.groupdict() model = get_model(matches['app_label'], matches['model_name']) if not model: - return self.redirect_to + return None try: instance = model._default_manager.get(pk=int(matches['pk'])) - return instance.get_absolute_url() + return instance except models.ObjectDoesNotExist: pass - return self.redirect_to + return None + + def get_redirect_to_target(self, request=None): + """ + This might be overriden/extended by extension modules. + """ + + target_page = self.get_redirect_to_page() + if target_page is None: + return self.redirect_to + + return target_page.get_absolute_url() @classmethod def path_to_cache_key(cls, path): From 470af4162c98087a32713f9dfd345102f615ea20 Mon Sep 17 00:00:00 2001 From: valmynd Date: Thu, 10 Dec 2015 01:50:36 +0100 Subject: [PATCH 1239/1590] make FeinCMS compatible with django-reversion >= 1.10 see http://django-reversion.readthedocs.org/en/latest/api.html see https://github.com/etianen/django-reversion/commit/755de5cc471b83b92aa731c0e58b452d205ed414 --- feincms/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index e40ac9411..6406b8619 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -820,7 +820,7 @@ def replace_content_with(self, obj): @classmethod def register_with_reversion(cls): try: - import reversion + from reversion import revisions as reversion except ImportError: raise EnvironmentError("django-reversion is not installed") From b3042a8f65718b6c81e547516c728fc281cda7a1 Mon Sep 17 00:00:00 2001 From: valmynd Date: Fri, 11 Dec 2015 10:35:16 +0100 Subject: [PATCH 1240/1590] make FeinCMS compatible with django-reversion >= 1.10, but also backwards compatible --- feincms/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index 6406b8619..53ec7be19 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -822,7 +822,10 @@ def register_with_reversion(cls): try: from reversion import revisions as reversion except ImportError: - raise EnvironmentError("django-reversion is not installed") + try: + import reversion + except ImportError: + raise EnvironmentError("django-reversion is not installed") follow = [] for content_type in cls._feincms_content_types: From f2fa08609048e145de4fc6e54a0fe7315481038a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 19 Aug 2015 09:35:55 +0200 Subject: [PATCH 1241/1590] Remove an empty file --- feincms/admin/thumbnail.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 feincms/admin/thumbnail.py diff --git a/feincms/admin/thumbnail.py b/feincms/admin/thumbnail.py deleted file mode 100644 index e69de29bb..000000000 From 1ce3145dac6f903df32f196e45c3cc1aba7ba8f2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 19 Aug 2015 09:36:05 +0200 Subject: [PATCH 1242/1590] Add comment to empty template --- tests/testapp/templates/feincms_base.html | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/testapp/templates/feincms_base.html b/tests/testapp/templates/feincms_base.html index e69de29bb..3cac88c3a 100644 --- a/tests/testapp/templates/feincms_base.html +++ b/tests/testapp/templates/feincms_base.html @@ -0,0 +1 @@ +{# only has to exist #} From b4b8963064cde77f044311fc22a114108aca6adc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 22 Aug 2015 10:07:26 +0200 Subject: [PATCH 1243/1590] Default setting update to TinyMCE 4.2 --- feincms/default_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 455c4ec22..dafe42a7e 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -48,7 +48,7 @@ FEINCMS_RICHTEXT_INIT_CONTEXT = getattr( settings, 'FEINCMS_RICHTEXT_INIT_CONTEXT', { - 'TINYMCE_JS_URL': '//tinymce.cachefly.net/4.1/tinymce.min.js', + 'TINYMCE_JS_URL': '//tinymce.cachefly.net/4.2/tinymce.min.js', 'TINYMCE_DOMAIN': None, 'TINYMCE_CONTENT_CSS_URL': None, 'TINYMCE_LINK_LIST_URL': None From 7cc9778527472ea262165cedb023fe5edf56189c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 29 Aug 2015 13:52:51 +0200 Subject: [PATCH 1244/1590] Allow running cov.sh without activated venv --- tests/cov.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cov.sh b/tests/cov.sh index e02eb0dd3..c577a1f65 100755 --- a/tests/cov.sh +++ b/tests/cov.sh @@ -1,3 +1,3 @@ #!/bin/sh -coverage run --branch --include="*feincms/feincms*" ./manage.py test testapp -coverage html +venv/bin/coverage run --branch --include="*feincms/feincms*" ./manage.py test testapp +venv/bin/coverage html From 5d856d04f37a8a214167f6b8fa7bf8ab9bf46e81 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 29 Aug 2015 16:28:44 +0200 Subject: [PATCH 1245/1590] Remove an unused, internal method --- feincms/extensions.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/feincms/extensions.py b/feincms/extensions.py index 6dcc37397..31773ff6f 100644 --- a/feincms/extensions.py +++ b/feincms/extensions.py @@ -92,13 +92,6 @@ def handle_modeladmin(self, modeladmin): pass -def _ensure_list(cls, attribute): - if cls is None: - return - value = getattr(cls, attribute, ()) or () - setattr(cls, attribute, list(value)) - - class ExtensionModelAdmin(admin.ModelAdmin): def __init__(self, *args, **kwargs): super(ExtensionModelAdmin, self).__init__(*args, **kwargs) From b2042235ffd8ceb6ae0d2c8d6ad3f501da15deac Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 29 Aug 2015 16:51:17 +0200 Subject: [PATCH 1246/1590] Move import to top of file (especially since we import this file anyway) --- feincms/module/page/extensions/navigation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 1254fbd6a..f49e86b00 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -22,7 +22,7 @@ from django.utils.translation import ugettext_lazy as _ from feincms import extensions -from feincms.utils import get_object +from feincms.utils import get_object, shorten_string from feincms._internal import monkeypatch_method @@ -80,7 +80,6 @@ def get_original_translation(self, page): return page def short_title(self): - from feincms.utils import shorten_string return shorten_string(self.title) From d2ebb36828245c498d2274b6055bfa8b9d21e133 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 31 Aug 2015 23:04:09 +0200 Subject: [PATCH 1247/1590] We do not need that, 3.2 and 3.4 are good enough --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 67e497146..9ea146933 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ python: - "2.6" - "2.7" - "3.2" - - "3.3" - "3.4" env: - DJANGO_REQUIREMENT="Django>=1.6,<1.7" From b32afffe90b8fca180059a954b09b8bea8bdbf5c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 3 Sep 2015 10:34:52 +0200 Subject: [PATCH 1248/1590] Stop crashing if `feincms_page` is None or "" --- feincms/templatetags/feincms_page_tags.py | 2 +- feincms/templatetags/feincms_tags.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index 6a56ccfd7..132a4b8f1 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -47,7 +47,7 @@ def feincms_nav(context, feincms_page, level=1, depth=1, group=None): page_class = _get_page_model() - if feincms_page is None: + if not feincms_page: return [] if isinstance(feincms_page, HttpRequest): diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 20d25e0cf..42da0e9e3 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -43,6 +43,9 @@ def feincms_render_region(context, feincms_object, region, request=None): """ {% feincms_render_region feincms_page "main" request %} """ + if not feincms_object: + return '' + return ''.join( _render_content(content, request=request, context=context) for content in getattr(feincms_object.content, region)) @@ -53,6 +56,9 @@ def feincms_render_content(context, content, request=None): """ {% feincms_render_content content request %} """ + if not content: + return '' + return _render_content(content, request=request, context=context) From 11c20b29eeba504bbdbdc8853a5e439699f8532c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 4 Sep 2015 21:23:48 +0200 Subject: [PATCH 1249/1590] .clear() also empties a dict --- feincms/module/extensions/ct_tracker.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 2065a45c4..44cd01fd4 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -126,8 +126,7 @@ def class_prepared_handler(sender, **kwargs): # are fully loaded and initialized when the translation map is accessed. # This leads to (lots of) crashes on the server. Better be safe and # kill the translation map when any class_prepared signal is received. - global _translation_map_cache - _translation_map_cache = {} + _translation_map_cache.clear() class_prepared.connect(class_prepared_handler) From 42b1f009ec351194049246b08296b538feb299e9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 8 Sep 2015 15:21:30 +0200 Subject: [PATCH 1250/1590] Fix #597: Boolean fields require default values --- feincms/module/extensions/featured.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index 6930a58a7..efc348096 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -12,7 +12,13 @@ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('featured', models.BooleanField(_('featured'))) + self.model.add_to_class( + 'featured', + models.BooleanField( + _('featured'), + default=False, + ), + ) if hasattr(self.model, 'cache_key_components'): self.model.cache_key_components.append(lambda page: page.featured) From e2cc400073c492192a014b036ba2356545ae1fdb Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:28:37 +0200 Subject: [PATCH 1251/1590] Prepare queryset_transform for Django 1.9 --- feincms/utils/queryset_transform.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index e2961965b..ac07ac2d9 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -90,9 +90,10 @@ class TransformQuerySet(models.query.QuerySet): def __init__(self, *args, **kwargs): super(TransformQuerySet, self).__init__(*args, **kwargs) self._transform_fns = [] + self._orig_iterable_class = getattr(self, '_iterable_class', None) - def _clone(self, klass=None, setup=False, **kw): - c = super(TransformQuerySet, self)._clone(klass, setup, **kw) + def _clone(self, *args, **kwargs): + c = super(TransformQuerySet, self)._clone(*args, **kwargs) c._transform_fns = self._transform_fns[:] return c @@ -103,12 +104,18 @@ def transform(self, *fn): def iterator(self): result_iter = super(TransformQuerySet, self).iterator() - if self._transform_fns: - results = list(result_iter) - for fn in self._transform_fns: - fn(results) - return iter(results) - return result_iter + + if not self._transform_fns: + return result_iter + + if getattr(self, '_iterable_class', None) != self._orig_iterable_class: + # Do not process the result of values() and values_list() + return result_iter + + results = list(result_iter) + for fn in self._transform_fns: + fn(results) + return iter(results) if hasattr(models.Manager, 'from_queryset'): From a11633a3e5a27c2a22f310980548d9726208f7af Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:38:00 +0200 Subject: [PATCH 1252/1590] The return value of feincms_render_region is safe --- feincms/templatetags/feincms_tags.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 42da0e9e3..a1820e1d1 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -8,6 +8,7 @@ from django import template from django.conf import settings +from django.utils.safestring import mark_safe from feincms.utils import get_singleton, get_singleton_url @@ -46,9 +47,9 @@ def feincms_render_region(context, feincms_object, region, request=None): if not feincms_object: return '' - return ''.join( + return mark_safe(''.join( _render_content(content, request=request, context=context) - for content in getattr(feincms_object.content, region)) + for content in getattr(feincms_object.content, region))) @register.simple_tag(takes_context=True) From d851a981409f957e722be1962bfd25986ad9d602 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 09:48:50 +0200 Subject: [PATCH 1253/1590] This certainly works --- feincms/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index e40ac9411..098eca43b 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -422,7 +422,7 @@ def _template(self): (template_.key, template_.title,) for template_ in cls._feincms_templates.values() ] - field.default = field.choices[0][0] + field.default = cls.TEMPLATE_CHOICES[0][0] # Build a set of all regions used anywhere cls._feincms_all_regions = set() From 7a046856a48659eb6fae630a80aae0ad019a37b6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 13 Oct 2015 10:59:51 +0200 Subject: [PATCH 1254/1590] Add a code of conduct --- CONTRIBUTING.rst | 19 +++++++++++++++++++ MANIFEST.in | 1 + 2 files changed, 20 insertions(+) create mode 100644 CONTRIBUTING.rst diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 000000000..ddf1d89ba --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,19 @@ +======================= +Contributing to FeinCMS +======================= + +Submission guidelines +===================== + +If you are creating a pull request, fork the repository and make any changes +in your own feature branch. + +Write and run tests. + + +Code of Conduct +=============== + +This project adheres to the +`Open Code of Conduct `_. +By participating, you are expected to honor this code. diff --git a/MANIFEST.in b/MANIFEST.in index 2b605a533..b8a1e6a53 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include AUTHORS +include CONTRIBUTING.rst include LICENSE include MANIFEST.in include README.rst From 27791206d17a11cef185d62d072e0a62f799a311 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 10:51:08 +0200 Subject: [PATCH 1255/1590] The prefix= argument has been removed, use semi-official API instead --- feincms/content/application/models.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index ccee39238..84c224a84 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -12,7 +12,9 @@ from django.conf import settings from django.core.cache import cache from django.core.urlresolvers import ( - Resolver404, resolve, reverse, NoReverseMatch) + Resolver404, resolve, reverse, NoReverseMatch, + get_script_prefix, set_script_prefix, +) from django.db import models from django.db.models import signals from django.http import HttpResponse @@ -54,7 +56,7 @@ def cycle_app_reverse_cache(*args, **kwargs): cycle_app_reverse_cache() -def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, +def app_reverse(viewname, urlconf=None, args=None, kwargs=None, *vargs, **vkwargs): """ Reverse URLs from application contents @@ -102,13 +104,17 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, if url_prefix: # vargs and vkwargs are used to send through additional parameters # which are uninteresting to us (such as current_app) - return reverse( - viewname, - url_prefix[0], - args=args, - kwargs=kwargs, - prefix=url_prefix[1], - *vargs, **vkwargs) + prefix = get_script_prefix() + try: + set_script_prefix(url_prefix[1]) + return reverse( + viewname, + url_prefix[0], + args=args, + kwargs=kwargs, + *vargs, **vkwargs) + finally: + set_script_prefix(prefix) raise NoReverseMatch("Unable to find ApplicationContent for %r" % urlconf) From 44cf2b92a2ab78c513b5a5623fbd8c4884f64733 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 10:03:41 +0200 Subject: [PATCH 1256/1590] Do not hardcode the change URL --- tests/testapp/tests/test_page.py | 40 +++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 3308db3a2..c0255606d 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -15,6 +15,8 @@ from django.core import mail from django.db import models from django.contrib.sites.models import Site +from django.core.urlresolvers import reverse +from django.db import models from django.http import Http404, HttpResponseBadRequest from django.template import TemplateDoesNotExist from django.template.defaultfilters import slugify @@ -178,10 +180,14 @@ def test_03_item_editor(self): self.login() self.assertRedirects( self.create_page_through_admin(_continue=1), - '/admin/page/page/1/') + reverse('admin:page_page_change', args=(1,))) self.assertEqual( - self.client.get('/admin/page/page/1/').status_code, 200) - self.is_published('/admin/page/page/42/', should_be=False) + self.client.get( + reverse('admin:page_page_change', args=(1,)) + ).status_code, 200) + self.is_published( + reverse('admin:page_page_change', args=(42,)), + should_be=False) def test_03_add_another(self): self.login() @@ -391,7 +397,9 @@ def create_page_through_admincontent(self, page, **kwargs): } data.update(kwargs) - return self.client.post('/admin/page/page/%s/' % page.pk, data) + return self.client.post( + reverse('admin:page_page_change', args=(page.pk,)), + data) def test_09_pagecontent(self): self.create_default_page_set() @@ -475,7 +483,7 @@ def test_10_mediafile_and_imagecontent(self): '%s-ha' % short_language_code() in mf.available_translations) # this should not raise - self.client.get('/admin/page/page/1/') + self.client.get(reverse('admin:page_page_change', args=(1,))) # self.assertTrue('alt="something"' in page.content.main[1].render()) # Since it isn't an image @@ -1210,7 +1218,9 @@ def test_24_admin_redirects(self): page = Page.objects.get(pk=1) response = self.create_page_through_admincontent(page, _continue=1) - self.assertRedirects(response, '/admin/page/page/1/') + self.assertRedirects( + response, + reverse('admin:page_page_change', args=(1,))) response = self.create_page_through_admincontent(page, _addanother=1) self.assertRedirects(response, '/admin/page/page/add/') @@ -1734,3 +1744,21 @@ def test_40_page_is_active(self): {'feincms_page': page1}, p, path='/test-page/whatsup/test/')) self.assertFalse(feincms_page_tags.page_is_active( {'feincms_page': page2}, p, path='/test-page/')) + + def test_41_templatecontent(self): + page = self.create_page() + template = page.templatecontent_set.create( + region=0, + ordering=1, + template='templatecontent_1.html', + ) + + self.assertEqual(template.render(), 'TemplateContent_1\n') + + # The empty form contains the template option. + self.login() + self.assertContains( + self.client.get( + reverse('admin:page_page_change', args=(page.id,)) + ), + '') From f5477728a9d38862b2c3f0148fb27614acfcbaf0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 30 Sep 2015 10:57:14 +0200 Subject: [PATCH 1257/1590] Fix more test failures --- feincms/module/medialibrary/modeladmins.py | 2 +- tests/testapp/applicationcontent_urls.py | 4 +-- tests/testapp/tests/test_page.py | 38 +++++++--------------- tests/testapp/tests/test_stuff.py | 13 ++++++-- 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 3bbd9da3a..6c701a3f2 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -183,7 +183,7 @@ def file_type(self, obj): d = get_image_dimensions(obj.file.file) if d: t += " %d×%d" % (d[0], d[1]) - except (IOError, ValueError) as e: + except (IOError, TypeError, ValueError) as e: t += " (%s)" % e return t file_type.admin_order_field = 'type' diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index a71092254..7b83b46bd 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -13,7 +13,7 @@ def module_root(request): - return 'module_root' + return HttpResponse('module_root') def args_test(request, kwarg1, kwarg2): @@ -33,7 +33,7 @@ def fragment(request): def redirect(request): - return HttpResponseRedirect('../') + return HttpResponseRedirect(request.build_absolute_uri('../')) def response(request): diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index c0255606d..a23a238f8 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1300,7 +1300,7 @@ def test_25_applicationcontent(self): self.assertRedirects( self.client.get(page.get_absolute_url() + 'redirect/'), - page.get_absolute_url()) + 'http://testserver' + page.get_absolute_url()) self.assertEqual( app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), @@ -1357,21 +1357,23 @@ def test_25_applicationcontent(self): # Ensure ApplicationContent's admin_fields support works properly self.login() - self.assertContains( - self.client.get('/admin/page/page/%d/' % page.id), - 'exclusive_subpages') - self.assertContains( - self.client.get('/admin/page/page/%d/' % page.id), - 'custom_field' + response = self.client.get( + reverse('admin:page_page_change', args=(page1.id,)) ) + self.assertContains(response, 'exclusive_subpages') + self.assertContains(response, 'custom_field') + + # Check if admin_fields get populated correctly app_ct = page.applicationcontent_set.all()[0] app_ct.parameters =\ '{"custom_field":"val42", "exclusive_subpages": false}' app_ct.save() - r = self.client.get('/admin/page/page/%d/' % page.id) - self.assertContains(r, 'val42') + response = self.client.get( + reverse('admin:page_page_change', args=(page1.id,)) + ) + self.assertContains(response, 'val42') def test_26_page_form_initial(self): self.create_default_page_set() @@ -1744,21 +1746,3 @@ def test_40_page_is_active(self): {'feincms_page': page1}, p, path='/test-page/whatsup/test/')) self.assertFalse(feincms_page_tags.page_is_active( {'feincms_page': page2}, p, path='/test-page/')) - - def test_41_templatecontent(self): - page = self.create_page() - template = page.templatecontent_set.create( - region=0, - ordering=1, - template='templatecontent_1.html', - ) - - self.assertEqual(template.render(), 'TemplateContent_1\n') - - # The empty form contains the template option. - self.login() - self.assertContains( - self.client.get( - reverse('admin:page_page_change', args=(page.id,)) - ), - '') diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 058e2235e..cf5c747e6 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -7,6 +7,7 @@ import doctest from django.contrib.auth.models import User +from django.core.urlresolvers import reverse from django.test import TestCase from django.utils.encoding import force_text @@ -131,7 +132,11 @@ def test_01_smoke_test_admin(self): self.assertEqual( self.client.get('/admin/blog/entry/').status_code, 200) self.assertEqual( - self.client.get('/admin/blog/entry/1/').status_code, 200) + self.client.get( + reverse('admin:blog_entry_change', args=(1,)), + ).status_code, + 200, + ) def test_02_translations(self): self.create_entries() @@ -148,4 +153,8 @@ def test_03_admin(self): self.assertEqual( self.client.get('/admin/blog/entry/').status_code, 200) self.assertEqual( - self.client.get('/admin/blog/entry/1/').status_code, 200) + self.client.get( + reverse('admin:blog_entry_change', args=(1,)) + ).status_code, + 200, + ) From 5e177da8fdd5abf29c5bfdaa5cfb5a255cd560de Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 10:28:24 +0100 Subject: [PATCH 1258/1590] Oops --- tests/testapp/tests/test_page.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index a23a238f8..b1bc1c300 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1358,7 +1358,7 @@ def test_25_applicationcontent(self): # Ensure ApplicationContent's admin_fields support works properly self.login() response = self.client.get( - reverse('admin:page_page_change', args=(page1.id,)) + reverse('admin:page_page_change', args=(page.id,)) ) self.assertContains(response, 'exclusive_subpages') @@ -1371,7 +1371,7 @@ def test_25_applicationcontent(self): '{"custom_field":"val42", "exclusive_subpages": false}' app_ct.save() response = self.client.get( - reverse('admin:page_page_change', args=(page1.id,)) + reverse('admin:page_page_change', args=(page.id,)) ) self.assertContains(response, 'val42') From 95e5857c5f19aaddea174fc4368d0814a3aa908d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 10:29:22 +0100 Subject: [PATCH 1259/1590] Travis: Django 1.9 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9ea146933..bfb7c34be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,12 +9,17 @@ env: - DJANGO_REQUIREMENT="Django>=1.6,<1.7" - DJANGO_REQUIREMENT="Django>=1.7,<1.8" - DJANGO_REQUIREMENT="Django>=1.8,<1.9" + - DJANGO_REQUIREMENT="Django>=1.9,<1.10" matrix: exclude: - python: "2.6" env: DJANGO_REQUIREMENT="Django>=1.7,<1.8" - python: "2.6" env: DJANGO_REQUIREMENT="Django>=1.8,<1.9" + - python: "2.6" + env: DJANGO_REQUIREMENT="Django>=1.9,<1.10" + - python: "3.2" + env: DJANGO_REQUIREMENT="Django>=1.9,<1.10" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q $DJANGO_REQUIREMENT django-mptt Pillow feedparser flake8 --use-mirrors From da33a6333925aee9fa1c1ca6b177d0f3617e2ff6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 10:31:51 +0100 Subject: [PATCH 1260/1590] flake8 --- feincms/admin/filters.py | 2 +- feincms/module/extensions/translations.py | 12 +++++++----- feincms/views/cbv/views.py | 3 ++- tests/testapp/tests/test_page.py | 2 -- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index 2f8f9c380..9a126299c 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -73,7 +73,7 @@ def __init__(self, f, request, params, model, model_admin, f, request, params, model, model_admin, field_path) # Restrict results to categories which are actually in use: - if DJANGO_VERSION < (1,8): + if DJANGO_VERSION < (1, 8): related_model = f.related.parent_model related_name = f.related.var_name else: diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 2a469a673..1ec9ee995 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -34,6 +34,8 @@ # ------------------------------------------------------------------------ logger = logging.getLogger(__name__) +LANGUAGE_COOKIE_NAME = django_settings.LANGUAGE_COOKIE_NAME + # ------------------------------------------------------------------------ def user_has_language_set(request): @@ -43,9 +45,9 @@ def user_has_language_set(request): site's language settings, after all, the user's decision is what counts. """ if (hasattr(request, 'session') - and request.session.get(django_settings.LANGUAGE_COOKIE_NAME) is not None): + and request.session.get(LANGUAGE_COOKIE_NAME) is not None): return True - if django_settings.LANGUAGE_COOKIE_NAME in request.COOKIES: + if LANGUAGE_COOKIE_NAME in request.COOKIES: return True return False @@ -85,8 +87,8 @@ def translation_set_language(request, select_language): if hasattr(request, 'session'): # User has a session, then set this language there - if select_language != request.session.get(django_settings.LANGUAGE_COOKIE_NAME): - request.session[django_settings.LANGUAGE_COOKIE_NAME] = select_language + if select_language != request.session.get(LANGUAGE_COOKIE_NAME): + request.session[LANGUAGE_COOKIE_NAME] = select_language elif request.method == 'GET' and not fallback: # No session is active. We need to set a cookie for the language # so that it persists when users change their location to somewhere @@ -95,7 +97,7 @@ def translation_set_language(request, select_language): # POST requests) response = HttpResponseRedirect(request.get_full_path()) response.set_cookie( - str(django_settings.LANGUAGE_COOKIE_NAME), select_language) + str(LANGUAGE_COOKIE_NAME), select_language) return response diff --git a/feincms/views/cbv/views.py b/feincms/views/cbv/views.py index 27b588bb2..496dcfbb6 100644 --- a/feincms/views/cbv/views.py +++ b/feincms/views/cbv/views.py @@ -45,7 +45,8 @@ def dispatch(self, request, *args, **kwargs): # page url. # Also clear out the _feincms_page attribute which caches # page lookups (and would just re-raise a 404). - request.path = request.path_info = settings.FEINCMS_CMS_404_PAGE + request.path = request.path_info =\ + settings.FEINCMS_CMS_404_PAGE if hasattr(request, '_feincms_page'): delattr(request, '_feincms_page') response = super(Handler, self).dispatch( diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index b1bc1c300..ea930cf06 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -13,7 +13,6 @@ from django.contrib.auth.models import User, AnonymousUser from django.contrib.contenttypes.models import ContentType from django.core import mail -from django.db import models from django.contrib.sites.models import Site from django.core.urlresolvers import reverse from django.db import models @@ -1364,7 +1363,6 @@ def test_25_applicationcontent(self): self.assertContains(response, 'exclusive_subpages') self.assertContains(response, 'custom_field') - # Check if admin_fields get populated correctly app_ct = page.applicationcontent_set.all()[0] app_ct.parameters =\ From b069e2d50faa46b5357208c2338569cf3c9bf81d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 10:36:59 +0100 Subject: [PATCH 1261/1590] No stable release of django-mptt supports Django 1.9, yet --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bfb7c34be..5d9bcf2b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ matrix: env: DJANGO_REQUIREMENT="Django>=1.9,<1.10" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - - pip install -q $DJANGO_REQUIREMENT django-mptt Pillow feedparser flake8 --use-mirrors + - pip install -q $DJANGO_REQUIREMENT https://github.com/django-mptt/django-mptt/archive/master.zip Pillow feedparser flake8 --use-mirrors - python setup.py -q install # command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && flake8 ." From 850ca08a9cf224b2a0ee0b69ba165edecc6e0731 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 10:39:38 +0100 Subject: [PATCH 1262/1590] Travis django-mptt again --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d9bcf2b7..3737baa93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,23 +6,23 @@ python: - "3.2" - "3.4" env: - - DJANGO_REQUIREMENT="Django>=1.6,<1.7" - - DJANGO_REQUIREMENT="Django>=1.7,<1.8" - - DJANGO_REQUIREMENT="Django>=1.8,<1.9" - - DJANGO_REQUIREMENT="Django>=1.9,<1.10" + - REQ="Django>=1.6,<1.7 django-mptt" + - REQ="Django>=1.7,<1.8 django-mptt" + - REQ="Django>=1.8,<1.9 django-mptt" + - REQ="Django>=1.9,<1.10 https://github.com/django-mptt/django-mptt/archive/master.zip" matrix: exclude: - python: "2.6" - env: DJANGO_REQUIREMENT="Django>=1.7,<1.8" + env: REQ="Django>=1.7,<1.8 django-mptt" - python: "2.6" - env: DJANGO_REQUIREMENT="Django>=1.8,<1.9" + env: REQ="Django>=1.8,<1.9 django-mptt" - python: "2.6" - env: DJANGO_REQUIREMENT="Django>=1.9,<1.10" + env: REQ="Django>=1.9,<1.10 django-mptt" - python: "3.2" - env: DJANGO_REQUIREMENT="Django>=1.9,<1.10" + env: REQ="Django>=1.9,<1.10 https://github.com/django-mptt/django-mptt/archive/master.zip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - - pip install -q $DJANGO_REQUIREMENT https://github.com/django-mptt/django-mptt/archive/master.zip Pillow feedparser flake8 --use-mirrors + - pip install -q $REQ Pillow feedparser flake8 --use-mirrors - python setup.py -q install # command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && flake8 ." From 81a59c8934f428f50877b24af28578154318f07b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 10:41:53 +0100 Subject: [PATCH 1263/1590] And again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3737baa93..c3311d5b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: - python: "2.6" env: REQ="Django>=1.8,<1.9 django-mptt" - python: "2.6" - env: REQ="Django>=1.9,<1.10 django-mptt" + env: REQ="Django>=1.9,<1.10 https://github.com/django-mptt/django-mptt/archive/master.zip" - python: "3.2" env: REQ="Django>=1.9,<1.10 https://github.com/django-mptt/django-mptt/archive/master.zip" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors From 9251c75b004a82b713a4366dd696d2cd1a1a808a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 10:48:44 +0100 Subject: [PATCH 1264/1590] FeinCMS v1.11.2 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 727a5281e..657f992a1 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 11, 1) +VERSION = (1, 11, 2) __version__ = '.'.join(map(str, VERSION)) From 8e43e13fc218b61f6a83a50eb682fc12e8274ed3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 12:08:27 +0100 Subject: [PATCH 1265/1590] Stop failing with admin.E023 --- feincms/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index a217b3fd1..ecbb9a952 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -399,7 +399,11 @@ def register_templates(cls, *templates): except (StopIteration,): cls.add_to_class( 'template_key', - models.CharField(_('template'), max_length=255, choices=()) + models.CharField(_('template'), max_length=255, choices=( + # Dummy choice to trick Django. Cannot be empty, + # otherwise admin.E023 happens. + ('base', 'base'), + )) ) field = next(iter( field for field in cls._meta.local_fields From b05e3878b0276002bda644a3c6f796a8fa357725 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 12:09:18 +0100 Subject: [PATCH 1266/1590] FeinCMS v1.11.3 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 657f992a1..3214ca367 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 11, 2) +VERSION = (1, 11, 3) __version__ = '.'.join(map(str, VERSION)) From e61262b974693071a61fb910129519645d74b543 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Dec 2015 15:34:33 +0100 Subject: [PATCH 1267/1590] Fix #598: models, not v2 --- docs/contenttypes.rst | 4 ++-- docs/medialibrary.rst | 2 +- feincms/content/medialibrary/models.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 6f1078760..2e5d61440 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -354,7 +354,7 @@ Additional arguments for :func:`~feincms.models.Base.create_content_type`: Media library integration ------------------------- -.. module:: feincms.content.medialibrary.v2 +.. module:: feincms.content.medialibrary.models .. class:: MediaFileContent() Mini-framework for arbitrary file types with customizable rendering @@ -552,7 +552,7 @@ do is adding a classmethod named :func:`initialize_type` to your content type, a pass additional keyword arguments to :func:`create_content_type`. If you want to see an example of these two uses, have a look at the -:class:`~feincms.content.medialibrary.v2.MediaFileContent`. +:class:`~feincms.content.medialibrary.models.MediaFileContent`. It is generally recommended to use this hook to configure content types compared to putting the configuration into the site-wide settings file. This diff --git a/docs/medialibrary.rst b/docs/medialibrary.rst index 48f26887f..67dda6efb 100644 --- a/docs/medialibrary.rst +++ b/docs/medialibrary.rst @@ -19,7 +19,7 @@ add :mod:`feincms.module.medialibrary` to your ``INSTALLED_APPS`` setting, and create a content type for a media file as follows:: from feincms.module.page.models import Page - from feincms.content.medialibrary.v2 import MediaFileContent + from feincms.content.medialibrary.models import MediaFileContent Page.create_content_type(MediaFileContent, TYPE_CHOICES=( ('default', _('default')), diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 43545662c..5a05080e2 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -26,7 +26,7 @@ class MediaFileContent(ContentWithMediaFile): Create a media file content as follows:: - from feincms.content.medialibrary.v2 import MediaFileContent + from feincms.content.medialibrary.models import MediaFileContent Page.create_content_type(MediaFileContent, TYPE_CHOICES=( ('default', _('Default')), ('lightbox', _('Lightbox')), From 133326f52c84e7271cabe7c315b4b80536186202 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 14 Dec 2015 15:44:21 +0100 Subject: [PATCH 1268/1590] Mark development version as such --- feincms/__init__.py | 2 +- setup.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 3214ca367..16d01c8d5 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 11, 3) +VERSION = (1, 11, 3, 'dev') __version__ = '.'.join(map(str, VERSION)) diff --git a/setup.py b/setup.py index 7de2162a6..5320bc2c8 100755 --- a/setup.py +++ b/setup.py @@ -10,10 +10,14 @@ def read(filename): with open(path, encoding='utf-8') as handle: return handle.read() +version = __import__('feincms').__version__ +devstatus = 'Development Status :: 5 - Production/Stable' +if '.dev' in version: + devstatus = 'Development Status :: 3 - Alpha' setup( name='FeinCMS', - version=__import__('feincms').__version__, + version=version, description='Django-based Page CMS and CMS building toolkit.', long_description=read('README.rst'), author='Matthias Kestenholz', @@ -45,7 +49,7 @@ def read(filename): 'pytz>=2014.10', ], classifiers=[ - 'Development Status :: 5 - Production/Stable', + devstatus, 'Environment :: Web Environment', 'Framework :: Django', 'Intended Audience :: Developers', From 169edd799f363ebaa67b566de7244bc837094cf6 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 14 Dec 2015 16:00:41 +0100 Subject: [PATCH 1269/1590] Bump for next version --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 16d01c8d5..e40dd5aba 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 11, 3, 'dev') +VERSION = (1, 11, 4, 'dev') __version__ = '.'.join(map(str, VERSION)) From d1eac6dac0801cddebf10296b6bfb8c84d85c78c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 17 Dec 2015 15:51:42 +0100 Subject: [PATCH 1270/1590] Fix #608: register_templates sets choices correctly with Django 1.9 --- feincms/models.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index ecbb9a952..c86725ceb 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -402,7 +402,7 @@ def register_templates(cls, *templates): models.CharField(_('template'), max_length=255, choices=( # Dummy choice to trick Django. Cannot be empty, # otherwise admin.E023 happens. - ('base', 'base'), + ('__dummy', '__dummy'), )) ) field = next(iter( @@ -422,10 +422,17 @@ def _template(self): cls.template = property(_template) - cls.TEMPLATE_CHOICES = field._choices = [ + cls.TEMPLATE_CHOICES = [ (template_.key, template_.title,) for template_ in cls._feincms_templates.values() ] + try: + # noqa https://github.com/django/django/commit/80e3444eca045799cc40e50c92609e852a299d38 + # Django 1.9 uses this code + field.choices = cls.TEMPLATE_CHOICES + except AttributeError: + # Older versions of Django use that. + field._choices = cls.TEMPLATE_CHOICES field.default = cls.TEMPLATE_CHOICES[0][0] # Build a set of all regions used anywhere From 65be0af4a10bb00fcf1b357b2af5d4bc44bd0e8a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 17 Dec 2015 16:10:26 +0100 Subject: [PATCH 1271/1590] FeinCMS v1.11.4 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 3214ca367..ea3f2640e 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 11, 3) +VERSION = (1, 11, 4) __version__ = '.'.join(map(str, VERSION)) From 02ee00c63ec7cba92dae1bfb02797721d0f278a1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 22 Dec 2015 14:59:41 +0100 Subject: [PATCH 1272/1590] mptt 0.8 is Django 1.8 or better only --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index c3311d5b4..8eafe1842 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,20 +6,20 @@ python: - "3.2" - "3.4" env: - - REQ="Django>=1.6,<1.7 django-mptt" - - REQ="Django>=1.7,<1.8 django-mptt" + - REQ="Django>=1.6,<1.7 django-mptt<0.8" + - REQ="Django>=1.7,<1.8 django-mptt<0.8" - REQ="Django>=1.8,<1.9 django-mptt" - - REQ="Django>=1.9,<1.10 https://github.com/django-mptt/django-mptt/archive/master.zip" + - REQ="Django>=1.9,<1.10 django-mptt" matrix: exclude: - python: "2.6" - env: REQ="Django>=1.7,<1.8 django-mptt" + env: REQ="Django>=1.7,<1.8 django-mptt<0.8" - python: "2.6" env: REQ="Django>=1.8,<1.9 django-mptt" - python: "2.6" - env: REQ="Django>=1.9,<1.10 https://github.com/django-mptt/django-mptt/archive/master.zip" + env: REQ="Django>=1.9,<1.10 django-mptt" - python: "3.2" - env: REQ="Django>=1.9,<1.10 https://github.com/django-mptt/django-mptt/archive/master.zip" + env: REQ="Django>=1.9,<1.10 django-mptt" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -q $REQ Pillow feedparser flake8 --use-mirrors From 306dc99627410336f8087ada72a603bfb6f8b5cc Mon Sep 17 00:00:00 2001 From: sperrygrove Date: Tue, 22 Dec 2015 11:03:58 +0000 Subject: [PATCH 1273/1590] Correct compatibility for django-reversion >= 1.10 --- feincms/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index c86725ceb..e740c886c 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -831,18 +831,18 @@ def replace_content_with(self, obj): @classmethod def register_with_reversion(cls): try: - from reversion import revisions as reversion + from reversion.revisions import register except ImportError: try: - import reversion + from reversion import register except ImportError: raise EnvironmentError("django-reversion is not installed") follow = [] for content_type in cls._feincms_content_types: follow.append('%s_set' % content_type.__name__.lower()) - reversion.register(content_type) - reversion.register(cls, follow=follow) + register(content_type) + register(cls, follow=follow) return Base From 49a5ec6e8f043d0d5df4f6a709a43ea2bd29c005 Mon Sep 17 00:00:00 2001 From: Fabian Germann Date: Wed, 23 Dec 2015 11:56:27 +0100 Subject: [PATCH 1274/1590] Pass config manually when registering CKE, otherwise the globally set format_tags take no effect --- feincms/templates/admin/content/richtext/init_ckeditor.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/templates/admin/content/richtext/init_ckeditor.html b/feincms/templates/admin/content/richtext/init_ckeditor.html index e92f6569f..d918c21f2 100644 --- a/feincms/templates/admin/content/richtext/init_ckeditor.html +++ b/feincms/templates/admin/content/richtext/init_ckeditor.html @@ -9,7 +9,7 @@ {% block config %} CKEDITOR.config.width = '787'; CKEDITOR.config.height= '300'; - // CKEDITOR.config.format_tags = 'p;h1;h2;h3;h4;pre'; + CKEDITOR.config.format_tags = 'p;h1;h2;h3;h4;pre'; CKEDITOR.config.toolbar = [ {% block toolbar %}['Maximize','-','Format','-','Bold','Italic','Underline','Strike','-','Subscript','Superscript','-','NumberedList','BulletedList','-','Anchor', 'Link','Unlink','-','Source']{% endblock %} ]; @@ -40,7 +40,7 @@ function feincms_richtext_add_ckeditor(field) { var id = field ? field.id : this.id; if (!(id in CKEDITOR.instances)) { - CKEDITOR.replace(id); + CKEDITOR.replace(id, CKEDITOR.config); } } From 3da926a4d1eac03a8ae6c3e13fc0dd861fc48238 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Date: Tue, 29 Dec 2015 14:37:06 +0530 Subject: [PATCH 1275/1590] docs(readme): update "FeinCMS in a Box" url --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e35e7ecdc..8762b52e7 100644 --- a/README.rst +++ b/README.rst @@ -80,7 +80,7 @@ Visit these sites Try out FeinCMS in a Box ------------------------ -`FeinCMS in a Box `_ is a +`FeinCMS in a Box `_ is a prepackaged installation of FeinCMS with a few additional modules and a setup script. Try it out! From 3084a4de9c9e2dc74f302599b484e2c0aedd86f0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 18 Jan 2016 12:47:25 +0100 Subject: [PATCH 1276/1590] Fix the breadcrumbs navigation customization (Django 1.9 change URL changed) --- feincms/templates/admin/feincms/page/page/item_editor.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/templates/admin/feincms/page/page/item_editor.html b/feincms/templates/admin/feincms/page/page/item_editor.html index 67cb03f22..94ce86d22 100644 --- a/feincms/templates/admin/feincms/page/page/item_editor.html +++ b/feincms/templates/admin/feincms/page/page/item_editor.html @@ -16,14 +16,14 @@ {% block breadcrumbs %}
    + {{ form }} + + + + +
     
    + + diff --git a/feincms/templates/content/contactform/thanks.html b/feincms/templates/content/contactform/thanks.html new file mode 100644 index 000000000..7ea197009 --- /dev/null +++ b/feincms/templates/content/contactform/thanks.html @@ -0,0 +1,4 @@ +{% load i18n %} +
    +

    {% trans "Thanks!" %}

    +
    diff --git a/feincms/templates/content/file/default.html b/feincms/templates/content/file/default.html new file mode 100644 index 000000000..2f1d5baf0 --- /dev/null +++ b/feincms/templates/content/file/default.html @@ -0,0 +1,4 @@ + + {{ content.title }} + ({{ content.file.size|filesizeformat }}) + diff --git a/feincms/templates/content/image/default.html b/feincms/templates/content/image/default.html new file mode 100644 index 000000000..2df317749 --- /dev/null +++ b/feincms/templates/content/image/default.html @@ -0,0 +1 @@ +
    {{ content.alt_text }}{% if content.caption %}
    {{ content.caption }}
    {% endif %}
    diff --git a/feincms/templates/content/section/default.html b/feincms/templates/content/section/default.html new file mode 100644 index 000000000..c55ccee9f --- /dev/null +++ b/feincms/templates/content/section/default.html @@ -0,0 +1,7 @@ +

    {{ content.title }}

    + +{% if content.mediafile %} + {{ content.mediafile }} +{% endif %} + +{{ content.richtext|safe }} diff --git a/feincms/templates/content/section/image.html b/feincms/templates/content/section/image.html new file mode 100644 index 000000000..396a3bbe1 --- /dev/null +++ b/feincms/templates/content/section/image.html @@ -0,0 +1,5 @@ +

    {{ content.title }}

    + + + +{{ content.richtext|safe }} diff --git a/feincms/templates/content/video/sf.html b/feincms/templates/content/video/sf.html new file mode 100644 index 000000000..168c4183a --- /dev/null +++ b/feincms/templates/content/video/sf.html @@ -0,0 +1,7 @@ + + + + + diff --git a/feincms/templates/content/video/unknown.html b/feincms/templates/content/video/unknown.html new file mode 100644 index 000000000..832f1e050 --- /dev/null +++ b/feincms/templates/content/video/unknown.html @@ -0,0 +1 @@ +{{ content.video }} diff --git a/feincms/templates/content/video/vimeo.html b/feincms/templates/content/video/vimeo.html new file mode 100644 index 000000000..9ec14ad3c --- /dev/null +++ b/feincms/templates/content/video/vimeo.html @@ -0,0 +1,2 @@ + diff --git a/feincms/templates/content/video/youtube.html b/feincms/templates/content/video/youtube.html new file mode 100644 index 000000000..2b5fec51c --- /dev/null +++ b/feincms/templates/content/video/youtube.html @@ -0,0 +1,6 @@ + + + + + diff --git a/feincms/views.py b/feincms/views/__init__.py similarity index 100% rename from feincms/views.py rename to feincms/views/__init__.py diff --git a/feincms/views/decorators.py b/feincms/views/decorators.py new file mode 100644 index 000000000..365761807 --- /dev/null +++ b/feincms/views/decorators.py @@ -0,0 +1,10 @@ +# flake8: noqa +from __future__ import absolute_import, unicode_literals + +import warnings + +from feincms.apps import * + +warnings.warn( + 'Import ApplicationContent and friends from feincms.apps.', + DeprecationWarning, stacklevel=2) From 7ba02535d2ce042ef4eb63fd622911553413f7d3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 15:21:53 +0100 Subject: [PATCH 1283/1590] That is actually incorrect --- docs/releases/1.12.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/releases/1.12.rst b/docs/releases/1.12.rst index b66f3e6db..7169e784b 100644 --- a/docs/releases/1.12.rst +++ b/docs/releases/1.12.rst @@ -65,8 +65,8 @@ Notable features and improvements * Rich text cleaning using Tidy has been removed. -* FeinCMS no longer comes with its own copy of jQuery — it reuses Django's - jQuery instead. +* ``FEINCMS_JQUERY_NO_CONFLICT`` is gone. Either use ``django.jQuery`` or + ``feincms.jQuery`` explicitly. * Some support has been added for ``django-filer``. From 80cc962fa7fdf8f5909cd2687fec93ef9b739b01 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 15:28:36 +0100 Subject: [PATCH 1284/1590] This is important --- docs/releases/1.12.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/releases/1.12.rst b/docs/releases/1.12.rst index 7169e784b..0e74b79b3 100644 --- a/docs/releases/1.12.rst +++ b/docs/releases/1.12.rst @@ -31,6 +31,10 @@ The blog module has been completely removed ============================================ +Caching of pages in various page manager methods has been removed +================================================================= + + Backwards-incompatible changes ============================== From daf78990ba74ac3df2daf04251cb0fea1fbc1e5c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 18 Jan 2016 12:47:25 +0100 Subject: [PATCH 1285/1590] Fix the breadcrumbs navigation customization (Django 1.9 change URL changed) --- feincms/templates/admin/feincms/page/page/item_editor.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/templates/admin/feincms/page/page/item_editor.html b/feincms/templates/admin/feincms/page/page/item_editor.html index 67cb03f22..94ce86d22 100644 --- a/feincms/templates/admin/feincms/page/page/item_editor.html +++ b/feincms/templates/admin/feincms/page/page/item_editor.html @@ -16,14 +16,14 @@ {% block breadcrumbs %} '); var panel = $(''); - panel.html(c); + var $elem = $(elem); + panel.append($elem.children('div')); + $elem.remove(); // Remove the rest panels.push(panel); }); option_wrapper.append('
    '); - $('#extension_options').html(panels); + $('#extension_options').append(panels); create_tabbed('#extension_options_wrapper', '#extension_options'); /* Done morphing extension options into tabs */ From 433683f273e6a5874fa7d33bc8fe888141b9ef61 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 16:04:16 +0100 Subject: [PATCH 1287/1590] Add a missing __init__ file --- feincms/content/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 feincms/content/__init__.py diff --git a/feincms/content/__init__.py b/feincms/content/__init__.py new file mode 100644 index 000000000..e69de29bb From 9ab82b232e23f749a13bcf5779e49392c54f41b1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 16:12:26 +0100 Subject: [PATCH 1288/1590] Add a note about TemplateContent migration to the release notes --- docs/releases/1.12.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/releases/1.12.rst b/docs/releases/1.12.rst index 0e74b79b3..9650e473c 100644 --- a/docs/releases/1.12.rst +++ b/docs/releases/1.12.rst @@ -26,6 +26,25 @@ be explicitly specified when creating the content type:: ('base.html', 'makes no sense'), ]) +Also, you need to add a model migration which renames the old +``filename`` field to the new ``template`` field:: + + # -*- coding: utf-8 -*- + from __future__ import unicode_literals + + from django.db import models, migrations + + + class Migration(migrations.Migration): + + dependencies = [ + ('page', 'WHATEVER IS APPROPRIATE'), + ] + + operations = [ + migrations.RenameField('TemplateContent', 'filename', 'template'), + ] + The blog module has been completely removed ============================================ From 94ffa872ac0a3addca8a8f8b26860b96f66826bd Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 16:36:36 +0100 Subject: [PATCH 1289/1590] Go through the docs once --- docs/contenttypes.rst | 48 ++++++++--------------------- docs/deprecation.rst | 6 ++++ docs/faq.rst | 25 --------------- docs/installation.rst | 4 +-- docs/integration.rst | 71 +++++++++++++++++++++---------------------- docs/medialibrary.rst | 37 +++++++++++----------- docs/page.rst | 50 ++++++++++++++++-------------- 7 files changed, 102 insertions(+), 139 deletions(-) diff --git a/docs/contenttypes.rst b/docs/contenttypes.rst index 2e5d61440..dbb365fd2 100644 --- a/docs/contenttypes.rst +++ b/docs/contenttypes.rst @@ -307,21 +307,12 @@ Bundled content types Application content ------------------- -.. module:: feincms.content.application.models +.. module:: feincms.apps .. class:: ApplicationContent() Used to let the administrator freely integrate 3rd party applications into the CMS. Described in :ref:`integration-applicationcontent`. - -Comments content ----------------- -.. module:: feincms.content.comments.models -.. class:: CommentsContent() - -Comment list and form using ``django.contrib.comments``. - - Contact form content -------------------- .. module:: feincms.content.contactform.models @@ -354,7 +345,7 @@ Additional arguments for :func:`~feincms.models.Base.create_content_type`: Media library integration ------------------------- -.. module:: feincms.content.medialibrary.models +.. module:: feincms.module.medialibrary.contents .. class:: MediaFileContent() Mini-framework for arbitrary file types with customizable rendering @@ -392,7 +383,7 @@ Additional arguments for :func:`~feincms.models.Base.create_content_type`: Raw content ----------- -.. module:: feincms.content.raw.models +.. module:: feincms.contents .. class:: RawContent() Raw HTML code, f.e. for flash movies or javascript code. @@ -400,7 +391,7 @@ Raw HTML code, f.e. for flash movies or javascript code. Rich text --------- -.. module:: feincms.content.richtext.models +.. module:: feincms.contents .. class:: RichTextContent() Rich text editor widget, stripped down to the essentials; no media support, @@ -458,18 +449,6 @@ To perform those operations ``contentblock_move_handlers.poorify`` -RSS feeds ---------- -.. module:: feincms.content.rss.models -.. class:: RSSContent - -A feed reader widget. This also serves as an example how to build a content -type that needs additional processing, in this case from a cron job. If an -RSS feed has been added to the CMS, ``manage.py update_rsscontent`` should -be run periodically (either through a cron job or through other means) to -keep the shown content up to date. The `feedparser` module is required. - - Section content --------------- .. module:: feincms.content.section.models @@ -480,17 +459,16 @@ Combined rich text editor, title and media file. Template content ---------------- -.. module:: feincms.content.template.models +.. module:: feincms.contents .. class:: TemplateContent() -This is a content type that just includes a snippet from a template. -This content type scans all template directories for templates below -``content/template/`` and allows the user to select one of these templates -which are then rendered using the Django template language. +This is a content type that just renders a template. The available +templates have to be specified when creating the content type:: -Note that some file extensions are automatically filtered so they will not -appear in the list, namely any filenames ending with ``.~`` or ``.tmp`` will -be ignored. + Page.create_content_type(TemplateContent, TEMPLATES=( + ('content/template/something1.html', _('Something 1')), + ('content/template/something2.html', _('Something 2')), + )) Also note that a template content is not sandboxed or specially rendered. Whatever a django template can do a TemplateContent snippet can do too, @@ -575,13 +553,13 @@ You could take advantage of the fact that ``create_content_type`` returns the created model:: from feincms.module.page.models import Page - from feincms.content.raw.models import RawContent + from feincms.contents import RawContent PageRawContent = Page.create_content_type(RawContent) Or you could use :func:`content_type_for`:: - from feincms.content.raw.models import RawContent + from feincms.contents import RawContent PageRawContent = Page.content_type_for(RawContent) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index 7b82e7f9f..9bc7fb74e 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -120,3 +120,9 @@ No deprecations. * ``Page.cache_key`` has never been used by FeinCMS itself and will therefore be removed in a future release. Comparable functionality has been available for a long time with ``Page.path_to_cache_key``. + + +1.12 +==== + +* TODO update this \ No newline at end of file diff --git a/docs/faq.rst b/docs/faq.rst index f019067ab..e6f323788 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -30,28 +30,3 @@ too big, it might be time to reconsider whether you really want to use the extension mechanism or if it might not be easier to start freshly, only using the editor admin classes, feincms.models.Base and maybe parts of the included PageManager... - - - -I run ``syncdb`` and get a message about missing columns in the page table -========================================================================== - -You enabled the page module (added :mod:`feincms.module.page` to -``INSTALLED_APPS``), run syncdb, and afterwards registered a few -extensions. The extensions you activated -(:mod:`~feincms.module.page.extensions.datepublisher` and -:mod:`~feincms.module.page.extensions.translations`) add new fields to -the page model, but your first ``syncdb`` did not know about them and -therefore did not create the columns for those extensions. - -You can either remove the line ``Page.register_extensions(...)`` from -your code or drop the page_page table and re-run ``syncdb``. If you want -to keep the pages you've already created, you need to figure out the -correct ALTER TABLE statements for your database yourself. - - - -Is FeinCMS version X compatible with Django version Y? -====================================================== - -Check out the compatibility matrix `here `_. diff --git a/docs/installation.rst b/docs/installation.rst index 7c29615e1..d6ed76246 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -9,8 +9,8 @@ Installation This document describes the steps needed to install FeinCMS. -FeinCMS requires a working installation of Django_ version 1.4, 1.5, 1.6 or -1.7. See the Django_ documentation for how to install and configure Django. +FeinCMS requires a working installation of Django_ version 1.7 or better +See the Django_ documentation for how to install and configure Django. You can download a stable release of FeinCMS using ``pip``. Pip will install feincms and its dependencies. Dependencies which are automatically installed diff --git a/docs/integration.rst b/docs/integration.rst index ad536471f..c3a3b3eb4 100644 --- a/docs/integration.rst +++ b/docs/integration.rst @@ -15,19 +15,19 @@ The default CMS handler view is ``feincms.views.cbv.handler``. You can add the following as last line in your ``urls.py`` to make a catch-all for any pages which were not matched before:: - from feincms.views.cbv.views import Handler + from feincms.views import Handler handler = Handler.as_view() - urlpatterns += patterns('', + urlpatterns += [ url(r'^$', handler, name='feincms_home'), url(r'^(.*)/$', handler, name='feincms_handler'), - ) + ] Note that this default handler can also take a keyword parameter ``path`` to specify which url to render. You can use that functionality to implement a default page by adding another entry to your ``urls.py``:: - from feincms.views.cbv.views import Handler + from feincms.views import Handler handler = Handler.as_view() ... @@ -41,9 +41,9 @@ of your own URL patterns like this:: # ... - urlpatterns += patterns('', + urlpatterns += [ url(r'', include('feincms.urls')), - ) + ] The URLconf entry names ``feincms_home`` and ``feincms_handler`` must both exist somewhere in your project. The standard ``feincms.urls`` @@ -95,20 +95,20 @@ can be too easily violated. An example ``urls.py`` follows:: - from django.conf.urls import patterns, include, url + from django.conf.urls import include, url from django.views.generic.detail import DetailView from django.views.generic.list import ListView from news.models import Entry - urlpatterns = patterns('', + urlpatterns = [ url(r'^$', ListView.as_view( queryset=Entry.objects.all(), ), name='entry_list'), url(r'^(?P[^/]+)/$', DetailView.as_view( queryset=Entry.objects.all(), ), name='entry_detail'), - ) + ] Please note that you should not add the ``news/`` prefix here. You should *not* reference this ``urls.py`` file anywhere in a ``include`` statement. @@ -124,7 +124,7 @@ It's as simple as that:: Page.create_content_type(ApplicationContent, APPLICATIONS=( ('news.urls', 'News application'), - )) + )) Writing the models @@ -135,12 +135,11 @@ reachable through standard means (remember, they aren't ``include``\d anywhere) it's not possible to use standard ``reverse`` calls to determine the absolute URL of a news entry. FeinCMS provides its own ``app_reverse`` function (see :ref:`integration-reversing-urls` for -details) and ``permalink`` decorator mimicking the interface of -Django's standard functionality:: +details) mimicking the interface of Django's standard functionality:: from django.db import models - from feincms.content.application import models as app_models + from feincms.apps import app_reverse class Entry(models.Model): title = models.CharField(max_length=200) @@ -153,26 +152,22 @@ Django's standard functionality:: def __str__(self): return self.title - @app_models.permalink def get_absolute_url(self): - return ('entry_detail', 'news.urls', (), { + return app_reverse('entry_detail', 'news.urls', kwargs={ 'slug': self.slug, - }) + }) The only difference is that you do not only have to specify the view name -(``entry_detail``) but also the URLconf file (``news.urls``) for this -specific ``permalink`` decorator. The URLconf string must correspond to the -specification used in the ``APPLICATIONS`` list in the ``create_content_type`` -call. +(``entry_detail``) but also the URLconf file (``news.urls``). The URLconf +string must correspond to the specification used in the ``APPLICATIONS`` +list in the ``create_content_type`` call. .. note:: - Previous FeinCMS versions only provided a monkey patched ``reverse`` + Old FeinCMS versions only provided a monkey patched ``reverse`` method with a slightly different syntax for reversing URLs. This - behavior is still available and as of now (FeinCMS 1.5) still active - by default. It is recommended to start using the new way right now - and add ``FEINCMS_REVERSE_MONKEY_PATCH = False`` to your settings file. + behavior has been removed some time ago. Returning content from views @@ -246,12 +241,14 @@ of any template rendering calls: ``urls.py``:: - from django.conf.urls import patterns, include, url + from django.conf.urls import url - urlpatterns = patterns('news.views', - url(r'^$', 'entry_list', name='entry_list'), - url(r'^(?P[^/]+)/$', 'entry_detail', name='entry_detail'), - ) + from news.views import entry_list, entry_detail + + urlpatterns = [ + url(r'^$', entry_list, name='entry_list'), + url(r'^(?P[^/]+)/$', entry_detail, name='entry_detail'), + ] The two templates referenced, ``news/entry_list.html`` and @@ -290,7 +287,7 @@ that it resolves URLs from application contents. The second argument, ``urlconf``, has to correspond to the URLconf parameter passed in the ``APPLICATIONS`` list to ``Page.create_content_type``:: - from feincms.content.application.models import app_reverse + from feincms.apps import app_reverse app_reverse('mymodel-detail', 'myapp.urls', args=...) or:: @@ -344,8 +341,8 @@ need them. All of these must be specified in the ``APPLICATIONS`` argument to Page.create_content_type(ApplicationContent, APPLICATIONS=( ('registration', 'Account creation and management', { 'urls': 'yourapp.registration_urls', - }), - ) + }), + ) * ``admin_fields``: Adding more fields to the application content interface: @@ -362,15 +359,15 @@ need them. All of these must be specified in the ``APPLICATIONS`` argument to required=False, initial=form.instance.parameters.get('exclusive_subpages', True), help_text=_('Exclude everything other than the application\'s content when rendering subpages.'), - ), - } + ), + } Page.create_content_type(ApplicationContent, APPLICATIONS=( ('registration', 'Account creation and management', { 'urls': 'yourapp.registration_urls', 'admin_fields': registration_admin_fields, - }), - ) + }), + ) The form fields will only be visible after saving the ``ApplicationContent`` for the first time. They are stored inside a JSON-encoded field. The values @@ -448,7 +445,7 @@ You don't need to do anything else as long as you use the built-in yield navigation.PagePretender( title=category.name, url=category.get_absolute_url(), - ) + ) class PassthroughExtension(navigation.NavigationExtension): name = 'passthrough extension' diff --git a/docs/medialibrary.rst b/docs/medialibrary.rst index 67dda6efb..1f81ce596 100644 --- a/docs/medialibrary.rst +++ b/docs/medialibrary.rst @@ -22,9 +22,9 @@ create a content type for a media file as follows:: from feincms.content.medialibrary.models import MediaFileContent Page.create_content_type(MediaFileContent, TYPE_CHOICES=( - ('default', _('default')), - ('lightbox', _('lightbox')), - )) + ('default', _('default')), + ('lightbox', _('lightbox')), + )) ``TYPE_CHOICES`` has nothing to do with file types -- it's about choosing @@ -59,19 +59,19 @@ find a template for rendering the The default set of pre-defined content types and recognition functions is:: MediaFileBase.register_filetypes( - ('image', _('Image'), lambda f: re.compile(r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), - ('video', _('Video'), lambda f: re.compile(r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv)$', re.IGNORECASE).search(f)), - ('audio', _('Audio'), lambda f: re.compile(r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), - ('pdf', _('PDF document'), lambda f: f.lower().endswith('.pdf')), - ('swf', _('Flash'), lambda f: f.lower().endswith('.swf')), - ('txt', _('Text'), lambda f: f.lower().endswith('.txt')), - ('rtf', _('Rich Text'), lambda f: f.lower().endswith('.rtf')), - ('zip', _('Zip archive'), lambda f: f.lower().endswith('.zip')), - ('doc', _('Microsoft Word'), lambda f: re.compile(r'\.docx?$', re.IGNORECASE).search(f)), - ('xls', _('Microsoft Excel'), lambda f: re.compile(r'\.xlsx?$', re.IGNORECASE).search(f)), - ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile(r'\.pptx?$', re.IGNORECASE).search(f)), - ('other', _('Binary'), lambda f: True), # Must be last - ) + ('image', _('Image'), lambda f: re.compile(r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), + ('video', _('Video'), lambda f: re.compile(r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv)$', re.IGNORECASE).search(f)), + ('audio', _('Audio'), lambda f: re.compile(r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), + ('pdf', _('PDF document'), lambda f: f.lower().endswith('.pdf')), + ('swf', _('Flash'), lambda f: f.lower().endswith('.swf')), + ('txt', _('Text'), lambda f: f.lower().endswith('.txt')), + ('rtf', _('Rich Text'), lambda f: f.lower().endswith('.rtf')), + ('zip', _('Zip archive'), lambda f: f.lower().endswith('.zip')), + ('doc', _('Microsoft Word'), lambda f: re.compile(r'\.docx?$', re.IGNORECASE).search(f)), + ('xls', _('Microsoft Excel'), lambda f: re.compile(r'\.xlsx?$', re.IGNORECASE).search(f)), + ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile(r'\.pptx?$', re.IGNORECASE).search(f)), + ('other', _('Binary'), lambda f: True), # Must be last + ) You can add to that set by calling ``MediaFile.register_filetypes()`` with your new file types similar to the above. @@ -115,8 +115,9 @@ To have a thumbnail preview in your ModelAdmin and Inline class:: class ImageForProject(models.Model): project = models.ForeignKey(Project) - mediafile = MediaFileForeignKey(MediaFile, related_name='+', - limit_choices_to={'type': 'image'}) + mediafile = MediaFileForeignKey( + MediaFile, related_name='+', + limit_choices_to={'type': 'image'}) For the maginfying-glass select widget in your content type inherit your inline diff --git a/docs/page.rst b/docs/page.rst index 5ddd3f24e..4c9a35ff5 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -21,7 +21,8 @@ To activate the page module, you need to follow the instructions in :ref:`installation` and afterwards add :mod:`feincms.module.page` to your :data:`INSTALLED_APPS`. -Before proceeding with ``manage.py syncdb``, it might be a good idea to take +Before proceeding with ``manage.py makemigrations`` and ``./manage.py migrate``, +it might be a good idea to take a look at :ref:`page-extensions` -- the page module does have the minimum of features in the default configuration and you will probably want to enable several extensions. @@ -36,13 +37,13 @@ by adding the following lines somewhere into your project, for example in a from django.utils.translation import ugettext_lazy as _ from feincms.module.page.models import Page - from feincms.content.richtext.models import RichTextContent - from feincms.content.medialibrary.models import MediaFileContent + from feincms.contents import RichTextContent + from feincms.module.medialibrary.contents import MediaFileContent Page.register_extensions( - 'feincms.module.extensions.datepublisher', - 'feincms.module.extensions.translations' - ) # Example set of extensions + 'feincms.extensions.datepublisher', + 'feincms.extensions.translations' + ) # Example set of extensions Page.register_templates({ 'title': _('Standard template'), @@ -84,6 +85,11 @@ richtext support:: 'TINYMCE_JS_URL': STATIC_URL + 'your_custom_path/tiny_mce.js', } +If you want to use a different admin site, or want to apply customizations to +the admin class used, add the following setting to your site-wide settings:: + + FEINCMS_USE_PAGE_ADMIN = False + Wiring up the views =================== @@ -92,9 +98,9 @@ Just add the following lines to your ``urls.py`` to get a catch-all URL pattern: :: - urlpatterns += patterns('', + urlpatterns += [ url(r'', include('feincms.urls')), - ) + ] If you want to define a page as home page for the whole site, you can give it @@ -159,37 +165,38 @@ upon registering the extension. The :func:`register` method receives the :class:`~feincms.module.page.modeladmins.PageAdmin` as arguments. The extensions can be activated as follows:: - Page.register_extensions('feincms.module.page.extensions.navigation', - 'feincms.module.page.extensions.titles', - 'feincms.module.extensions.translations') + Page.register_extensions( + 'feincms.module.page.extensions.navigation', + 'feincms.module.page.extensions.titles', + 'feincms.extensions.translations') The following extensions are available currently: -* :mod:`feincms.module.extensions.changedate` --- Creation and modification dates +* :mod:`feincms.extensions.changedate` --- Creation and modification dates Adds automatically maintained creation and modification date fields to the page. -* :mod:`feincms.module.extensions.ct_tracker` --- Content type cache +* :mod:`feincms.extensions.ct_tracker` --- Content type cache Helps reduce database queries if you have three or more content types. -* :mod:`feincms.module.extensions.datepublisher` --- Date-based publishing +* :mod:`feincms.extensions.datepublisher` --- Date-based publishing Adds publication date and end date fields to the page, thereby enabling the administrator to define a date range where a page will be available to website visitors. -* :mod:`feincms.module.page.extensions.excerpt` --- Page summary +* :mod:`feincms.page.extensions.excerpt` --- Page summary Add a brief excerpt summarizing the content of this page. -* :mod:`feincms.module.extensions.featured` --- Simple featured flag for a page +* :mod:`feincms.extensions.featured` --- Simple featured flag for a page Lets administrators set a featured flag that lets you treat that page special. @@ -214,7 +221,7 @@ The following extensions are available currently: Add a many-to-many relationship field to relate this page to other pages. -* :mod:`feincms.module.extensions.seo` --- Search engine optimization +* :mod:`feincms.extensions.seo` --- Search engine optimization Adds fields to the page relevant for search engine optimization (SEO), currently only meta keywords and description. @@ -240,7 +247,7 @@ The following extensions are available currently: content area. -* :mod:`feincms.module.extensions.translations` --- Page translations +* :mod:`feincms.extensions.translations` --- Page translations Adds a language field and a recursive translations many to many field to the page, so that you can define the language the page is in and assign @@ -262,8 +269,7 @@ The following extensions are available currently: .. note:: These extension modules add new fields to the ``Page`` class. If you add or - remove page extensions after you've run ``syncdb`` for the first time you - have to change the database schema yourself, or use :ref:`migrations`. + remove page extensions you make and apply new migrations. Using page request processors @@ -379,10 +385,10 @@ Feincms site, add the following to your top-level urls.py:: from feincms.module.page.sitemap import PageSitemap sitemaps = {'pages' : PageSitemap} - urlpatterns += patterns('', + urlpatterns += [ url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}), - ) + ] This will produce a default sitemap at the /sitemap.xml url. A sitemap can be further customised by passing it appropriate parameters, like so:: From 08b86de557e5710e9a0841a72a68890cc50335cc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 17:01:12 +0100 Subject: [PATCH 1290/1590] Fix #602: Add a note that when using ct_tracker, simply adding content blocks is not enough --- docs/page.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/page.rst b/docs/page.rst index 4c9a35ff5..e54a460e6 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -181,7 +181,11 @@ The following extensions are available currently: * :mod:`feincms.extensions.ct_tracker` --- Content type cache - Helps reduce database queries if you have three or more content types. + Helps reduce database queries if you have three or more content types by + caching in the database which content types are available on each page. + If this extension is used, ``Page._ct_inventory`` has to be nullified + after adding and/or removing content blocks, otherwise changes might not + be visible in the frontend. Saving the page instance accomplishes this. * :mod:`feincms.extensions.datepublisher` --- Date-based publishing From e38bffcb423d74a8f784993f260ce333be036795 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 17:06:04 +0100 Subject: [PATCH 1291/1590] makemigrations/migrate are a requirement --- docs/migrations.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/migrations.rst b/docs/migrations.rst index 6680c765a..ce17272c3 100644 --- a/docs/migrations.rst +++ b/docs/migrations.rst @@ -12,7 +12,11 @@ add migrations for FeinCMS models yourself inside your project. Django's builtin migrations =========================== -* Create a new folder in your app with an empty ``__init__.py`` inside. +This guide assumes that you are using both the page and the medialibrary +module from FeinCMS. Simply leave out medialibrary if unused. + +* Create a new folder named ``migrate`` in your app with an empty + ``__init__.py`` inside. * Add the following configuration to your ``settings.py``:: MIGRATION_MODULES = { @@ -24,3 +28,9 @@ Django's builtin migrations You **must not** use ``migrations`` as folder name for the FeinCMS migrations, otherwise Django **will** get confused. + +* Create initial migrations and apply them:: + + ./manage.py makemigrations medialibrary + ./manage.py makemigrations page + ./manage.py migrate From dd6601aee255ea0d2615430f7db5f03b1ce3f7ae Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 17:20:51 +0100 Subject: [PATCH 1292/1590] Update AUTHORS --- .mailmap | 1 + AUTHORS | 118 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/.mailmap b/.mailmap index 4cd2bdad0..68466507e 100644 --- a/.mailmap +++ b/.mailmap @@ -13,3 +13,4 @@ Skylar Saveland Stephan Jaekel Simon Bächler Simon Bächler +Matthias Kestenholz diff --git a/AUTHORS b/AUTHORS index 2deabd630..5f6987dd0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,101 +6,107 @@ The authors of FeinCMS are: * Simon Meers * Bojan Mihelac * Simon Bächler -* Bjorn Post * Stephan Jaekel +* Bjorn Post * Julien Phalip * Daniel Renz -* Stefan Reinhard -* Simon Schürpf * Matt Dawson +* Simon Schürpf * Skylar Saveland +* Stefan Reinhard * Peter Schmidt * Marc Egli * Psyton * Simon Schmid * Greg Turner * Charlie Denton +* Maarten van Gompel (proycon) * Bjarni Thorisson * Greg Taylor -* Maarten van Gompel (proycon) -* Urs Breton * Jonas +* Urs Breton * Antoni Aloy * Julian Bez -* Afonso Fernández Nogueira * Vítor Figueiró -* Sander van Leeuwen -* Martin Mahner -* Toby White +* Fabian Germann * Marc Tamlyn -* Nico Echaniz +* Martin Mahner * Max Peterson -* adsworth +* Nico Echaniz +* Sander van Leeuwen +* Toby White +* Afonso Fernández Nogueira * Brian Macdonald -* Gabriel Kovacs -* Maarten Draijer -* Andrew D. Ball -* Emmanuelle Delescolle * Torkn +* Emmanuelle Delescolle +* adsworth +* Maarten Draijer +* Gabriel Kovacs * Eric Delord -* tayg -* Cellarosi Marco -* Denis Popov -* Fabian Germann -* Fabian Vogler -* Håvard Grimelid +* Andrew D. Ball +* Michael Kutý +* Mikhail Korobov +* valmynd +* Wil Tan * Maciek Szczesniak * Marco Fucci -* Michael Bashkirov -* Mikhail Korobov * Perry Roper +* Denis Popov +* Cellarosi Marco * Raphael Jasjukaitis +* Håvard Grimelid * Richard A +* Michael Bashkirov +* tayg +* Fabian Vogler * Vaclav Klecanda -* Wil Tan -* Matthias K -* Jimmy Ye -* Alex Kamedov -* antiflu -* Mikkel Hoegh -* Jay Yu -* Olekasnadr Gula -* Paul Garner -* feczo -* Harro van der Klauw -* Piet Delport -* Gwildor Sok -* ilmarsm * Riccardo Coroneo -* niklaushug * Richard Bolt * Rico Moorman -* Giorgos Logiotatidis +* svleeuwen +* Saurabh Kumar * Sebastian Hillig * Silvan Spross -* George Karpenkov -* Domas Lapinskas -* Denis Martinez -* David Evans -* Darryl Woods -* Daniele Procida * Artur Barseghyan -* Sumit Datta -* Sun Liwen -* Tobias Haffner -* Anshuman Bhaduri +* Harro van der Klauw * Andrin Heusser * Andrey Popelo -* svleeuwen -* Valtron * Andi Albrecht +* Alex Kamedov +* Sumit Datta +* Sun Liwen +* Tobias Haffner * Alen Mujezinovic +* Valtron * Wim Feijen -* Marco Cellarosi * Wouter van der Graaf -* Mark Renton -* Livio Lunin +* antiflu +* feczo +* George Karpenkov +* Giorgos Logiotatidis +* Erik Stein +* Gwildor Sok +* Anshuman Bhaduri +* Jay Yu +* Jimmy Ye +* Jonas Svensson +* Domas Lapinskas +* Kevin Etienne * Laurent Paoletti +* Livio Lunin +* Denis Martinez +* David Evans +* i-trofimtschuk +* Marco Cellarosi +* Mark Renton +* Darryl Woods +* ilmarsm * Mason Hugus -* Kevin Etienne -* Jonas Svensson +* Daniele Procida +* Dan Büschlen +* niklaushug +* Mikkel Hoegh +* sperrygrove +* Olekasnadr Gula +* Paul Garner +* Piet Delport From aee69fa98b6f578085ef3eb3f64f777223096657 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 15:58:55 +0100 Subject: [PATCH 1293/1590] Stop reevaluating inline scripts in collapsed admin fieldsets for no reason at all --- feincms/static/feincms/item_editor.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index a7ddf71df..55920df96 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -377,11 +377,8 @@ options_fieldsets.each(function(idx, elem) { var option_title = $('h2', $(elem)).text(); - var c = $(elem).children('div'); var id_base = 'extension_option_'+ idx; - $(elem).remove(); - var paren = option_title.indexOf(' ('); if(paren > 0) option_title = option_title.substr(0, paren); @@ -390,12 +387,14 @@ option_title + '
    '); var panel = $(''); - panel.html(c); + var $elem = $(elem); + panel.append($elem.children('div')); + $elem.remove(); // Remove the rest panels.push(panel); }); option_wrapper.append('
    '); - $('#extension_options').html(panels); + $('#extension_options').append(panels); create_tabbed('#extension_options_wrapper', '#extension_options'); /* Done morphing extension options into tabs */ From 6ca79f5dafd60b818af279716ec1c067c34934e7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 17:20:51 +0100 Subject: [PATCH 1294/1590] Update AUTHORS --- .mailmap | 1 + AUTHORS | 118 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/.mailmap b/.mailmap index 4cd2bdad0..68466507e 100644 --- a/.mailmap +++ b/.mailmap @@ -13,3 +13,4 @@ Skylar Saveland Stephan Jaekel Simon Bächler Simon Bächler +Matthias Kestenholz diff --git a/AUTHORS b/AUTHORS index 2deabd630..5f6987dd0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,101 +6,107 @@ The authors of FeinCMS are: * Simon Meers * Bojan Mihelac * Simon Bächler -* Bjorn Post * Stephan Jaekel +* Bjorn Post * Julien Phalip * Daniel Renz -* Stefan Reinhard -* Simon Schürpf * Matt Dawson +* Simon Schürpf * Skylar Saveland +* Stefan Reinhard * Peter Schmidt * Marc Egli * Psyton * Simon Schmid * Greg Turner * Charlie Denton +* Maarten van Gompel (proycon) * Bjarni Thorisson * Greg Taylor -* Maarten van Gompel (proycon) -* Urs Breton * Jonas +* Urs Breton * Antoni Aloy * Julian Bez -* Afonso Fernández Nogueira * Vítor Figueiró -* Sander van Leeuwen -* Martin Mahner -* Toby White +* Fabian Germann * Marc Tamlyn -* Nico Echaniz +* Martin Mahner * Max Peterson -* adsworth +* Nico Echaniz +* Sander van Leeuwen +* Toby White +* Afonso Fernández Nogueira * Brian Macdonald -* Gabriel Kovacs -* Maarten Draijer -* Andrew D. Ball -* Emmanuelle Delescolle * Torkn +* Emmanuelle Delescolle +* adsworth +* Maarten Draijer +* Gabriel Kovacs * Eric Delord -* tayg -* Cellarosi Marco -* Denis Popov -* Fabian Germann -* Fabian Vogler -* Håvard Grimelid +* Andrew D. Ball +* Michael Kutý +* Mikhail Korobov +* valmynd +* Wil Tan * Maciek Szczesniak * Marco Fucci -* Michael Bashkirov -* Mikhail Korobov * Perry Roper +* Denis Popov +* Cellarosi Marco * Raphael Jasjukaitis +* Håvard Grimelid * Richard A +* Michael Bashkirov +* tayg +* Fabian Vogler * Vaclav Klecanda -* Wil Tan -* Matthias K -* Jimmy Ye -* Alex Kamedov -* antiflu -* Mikkel Hoegh -* Jay Yu -* Olekasnadr Gula -* Paul Garner -* feczo -* Harro van der Klauw -* Piet Delport -* Gwildor Sok -* ilmarsm * Riccardo Coroneo -* niklaushug * Richard Bolt * Rico Moorman -* Giorgos Logiotatidis +* svleeuwen +* Saurabh Kumar * Sebastian Hillig * Silvan Spross -* George Karpenkov -* Domas Lapinskas -* Denis Martinez -* David Evans -* Darryl Woods -* Daniele Procida * Artur Barseghyan -* Sumit Datta -* Sun Liwen -* Tobias Haffner -* Anshuman Bhaduri +* Harro van der Klauw * Andrin Heusser * Andrey Popelo -* svleeuwen -* Valtron * Andi Albrecht +* Alex Kamedov +* Sumit Datta +* Sun Liwen +* Tobias Haffner * Alen Mujezinovic +* Valtron * Wim Feijen -* Marco Cellarosi * Wouter van der Graaf -* Mark Renton -* Livio Lunin +* antiflu +* feczo +* George Karpenkov +* Giorgos Logiotatidis +* Erik Stein +* Gwildor Sok +* Anshuman Bhaduri +* Jay Yu +* Jimmy Ye +* Jonas Svensson +* Domas Lapinskas +* Kevin Etienne * Laurent Paoletti +* Livio Lunin +* Denis Martinez +* David Evans +* i-trofimtschuk +* Marco Cellarosi +* Mark Renton +* Darryl Woods +* ilmarsm * Mason Hugus -* Kevin Etienne -* Jonas Svensson +* Daniele Procida +* Dan Büschlen +* niklaushug +* Mikkel Hoegh +* sperrygrove +* Olekasnadr Gula +* Paul Garner +* Piet Delport From 3a857b29ad5b56adb70d69bae54db796944b1617 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 4 Feb 2016 17:01:12 +0100 Subject: [PATCH 1295/1590] Fix #602: Add a note that when using ct_tracker, simply adding content blocks is not enough --- docs/page.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/page.rst b/docs/page.rst index 5ddd3f24e..7ce79bc93 100644 --- a/docs/page.rst +++ b/docs/page.rst @@ -174,7 +174,11 @@ The following extensions are available currently: * :mod:`feincms.module.extensions.ct_tracker` --- Content type cache - Helps reduce database queries if you have three or more content types. + Helps reduce database queries if you have three or more content types by + caching in the database which content types are available on each page. + If this extension is used, ``Page._ct_inventory`` has to be nullified + after adding and/or removing content blocks, otherwise changes might not + be visible in the frontend. Saving the page instance accomplishes this. * :mod:`feincms.module.extensions.datepublisher` --- Date-based publishing From 0a52a9f40953313deef4d56e394adae5dd888e7a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Feb 2016 14:32:37 +0100 Subject: [PATCH 1296/1590] Move contents back to feincms.content to minimize the diff Splitting up into packages may follow, but that would be something different. --- feincms/content/filer/__init__.py | 0 feincms/content/filer/models.py | 117 ++++++++++++++++ feincms/content/raw/models.py | 26 +++- feincms/content/richtext/models.py | 49 ++++++- feincms/content/template/models.py | 41 +++++- feincms/contents.py | 206 +---------------------------- 6 files changed, 219 insertions(+), 220 deletions(-) create mode 100644 feincms/content/filer/__init__.py create mode 100644 feincms/content/filer/models.py diff --git a/feincms/content/filer/__init__.py b/feincms/content/filer/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/feincms/content/filer/models.py b/feincms/content/filer/models.py new file mode 100644 index 000000000..634dd4ba7 --- /dev/null +++ b/feincms/content/filer/models.py @@ -0,0 +1,117 @@ +from __future__ import absolute_import, unicode_literals + +from django.contrib import admin +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ + +from feincms.admin.item_editor import FeinCMSInline + +try: + from filer.fields.file import FilerFileField + from filer.fields.image import FilerImageField +except ImportError: + __all__ = () + +else: + + __all__ = ( + 'MediaFileContentInline', 'ContentWithFilerFile', + 'FilerFileContent', 'FilerImageContent', + ) + + class MediaFileContentInline(FeinCMSInline): + radio_fields = {'type': admin.VERTICAL} + + class ContentWithFilerFile(models.Model): + """ + File content + """ + feincms_item_editor_inline = MediaFileContentInline + + class Meta: + abstract = True + + def render(self, **kwargs): + ctx = {'content': self} + ctx.update(kwargs) + return render_to_string([ + 'content/filer/%s_%s.html' % (self.file_type, self.type), + 'content/filer/%s.html' % self.type, + 'content/filer/%s.html' % self.file_type, + 'content/filer/default.html', + ], ctx, context_instance=kwargs.get('context')) + + class FilerFileContent(ContentWithFilerFile): + mediafile = FilerFileField(verbose_name=_('file'), related_name='+') + file_type = 'file' + type = 'download' + + class Meta: + abstract = True + verbose_name = _('file') + verbose_name_plural = _('files') + + class FilerImageContent(ContentWithFilerFile): + """ + Create a media file content as follows:: + + from feincms.contents import FilerImageContent + Page.create_content_type(FilerImageContent, TYPE_CHOICES=( + ('inline', _('Default')), + ('lightbox', _('Lightbox')), + ('whatever', _('Whatever')), + )) + + For a media file of type 'image' and type 'lightbox', the following + templates are tried in order: + + * content/mediafile/image_lightbox.html + * content/mediafile/lightbox.html + * content/mediafile/image.html + * content/mediafile/default.html + + The context contains ``content`` and ``request`` (if available). + + The content.mediafile attribute are as follows (selection): + label, description, default_caption, default_alt_text, + author, must_always_publish_author_credit, + must_always_publish_copyright, date_taken, file, id, is_public, url + """ + + mediafile = FilerImageField(verbose_name=_('image'), related_name='+') + caption = models.CharField( + _('caption'), + max_length=1000, + blank=True, + ) + url = models.CharField( + _('URL'), + max_length=1000, + blank=True, + ) + + file_type = 'image' + + class Meta: + abstract = True + verbose_name = _('image') + verbose_name_plural = _('images') + + @classmethod + def initialize_type(cls, TYPE_CHOICES=None): + if TYPE_CHOICES is None: + raise ImproperlyConfigured( + 'You have to set TYPE_CHOICES when' + ' creating a %s' % cls.__name__) + + cls.add_to_class( + 'type', + models.CharField( + _('type'), + max_length=20, + choices=TYPE_CHOICES, + default=TYPE_CHOICES[0][0], + ), + ) diff --git a/feincms/content/raw/models.py b/feincms/content/raw/models.py index 7b23f8b74..487c5a241 100644 --- a/feincms/content/raw/models.py +++ b/feincms/content/raw/models.py @@ -1,10 +1,24 @@ -# flake8: noqa from __future__ import absolute_import, unicode_literals -import warnings +from django.db import models +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ -from feincms.contents import RawContent -warnings.warn( - 'Import RawContent from feincms.contents.', - DeprecationWarning, stacklevel=2) +class RawContent(models.Model): + """ + Content type which can be used to input raw HTML code into the CMS. + + The content isn't escaped and can be used to insert CSS or JS + snippets too. + """ + + text = models.TextField(_('content'), blank=True) + + class Meta: + abstract = True + verbose_name = _('raw content') + verbose_name_plural = _('raw contents') + + def render(self, **kwargs): + return mark_safe(self.text) diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 28f6b8481..e32ee4c09 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -1,10 +1,47 @@ -# flake8: noqa from __future__ import absolute_import, unicode_literals -import warnings +from django.db import models +from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ -from feincms.contents import RichTextContent +from feincms import settings +from feincms.contrib.richtext import RichTextField -warnings.warn( - 'Import RichTextContent from feincms.contents.', - DeprecationWarning, stacklevel=2) + +class RichTextContent(models.Model): + """ + Rich text content. Uses TinyMCE by default, but can be configured to do + anything you want using ``FEINCMS_RICHTEXT_INIT_CONTEXT`` and + ``FEINCMS_RICHTEXT_INIT_TEMPLATE``. + + If you are using TinyMCE 4.x then ``FEINCMS_RICHTEXT_INIT_TEMPLATE`` + needs to be set to ``admin/content/richtext/init_tinymce4.html``. + + Optionally runs the HTML code through HTML cleaners if you specify + ``cleanse=True`` when calling ``create_content_type``. + """ + + feincms_item_editor_context_processors = ( + lambda x: settings.FEINCMS_RICHTEXT_INIT_CONTEXT, + ) + feincms_item_editor_includes = { + 'head': [settings.FEINCMS_RICHTEXT_INIT_TEMPLATE], + } + + class Meta: + abstract = True + verbose_name = _('rich text') + verbose_name_plural = _('rich texts') + + def render(self, **kwargs): + return render_to_string( + 'content/richtext/default.html', + {'content': self}, + context_instance=kwargs.get('context')) + + @classmethod + def initialize_type(cls, cleanse=None): + cls.add_to_class( + 'text', + RichTextField(_('text'), blank=True, cleanse=cleanse), + ) diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 0af3ce5b4..1060e1235 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -1,10 +1,39 @@ -# flake8: noqa from __future__ import absolute_import, unicode_literals -import warnings +from django.db import models +from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ -from feincms.contents import TemplateContent +from feincms.content.raw.models import RawContent # noqa +from feincms.content.richtext.models import RichTextContent # noqa -warnings.warn( - 'Import TemplateContent from feincms.contents.', - DeprecationWarning, stacklevel=2) + +class TemplateContent(models.Model): + """ + Pass a list of templates when creating this content type. It uses the + default template system:: + + Page.create_content_type(TemplateContent, TEMPLATES=[ + ('content/template/something1.html', 'something'), + ('content/template/something2.html', 'something else'), + ('base.html', 'makes no sense'), + ]) + """ + class Meta: + abstract = True + verbose_name = _('template content') + verbose_name_plural = _('template contents') + + @classmethod + def initialize_type(cls, TEMPLATES): + cls.add_to_class('template', models.CharField( + _('template'), + max_length=100, + choices=TEMPLATES, + )) + + def render(self, **kwargs): + return render_to_string( + self.template, + {'content': self}, + context_instance=kwargs.get('context')) diff --git a/feincms/contents.py b/feincms/contents.py index 76f4253d9..9dc37f9a7 100644 --- a/feincms/contents.py +++ b/feincms/contents.py @@ -1,204 +1,6 @@ from __future__ import absolute_import, unicode_literals -from django.contrib import admin -from django.core.exceptions import ImproperlyConfigured -from django.db import models -from django.template.loader import render_to_string -from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ - -from feincms import settings -from feincms.admin.item_editor import FeinCMSInline -from feincms.contrib.richtext import RichTextField - - -class RawContent(models.Model): - """ - Content type which can be used to input raw HTML code into the CMS. - - The content isn't escaped and can be used to insert CSS or JS - snippets too. - """ - - text = models.TextField(_('content'), blank=True) - - class Meta: - abstract = True - verbose_name = _('raw content') - verbose_name_plural = _('raw contents') - - def render(self, **kwargs): - return mark_safe(self.text) - - -class RichTextContent(models.Model): - """ - Rich text content. Uses TinyMCE by default, but can be configured to do - anything you want using ``FEINCMS_RICHTEXT_INIT_CONTEXT`` and - ``FEINCMS_RICHTEXT_INIT_TEMPLATE``. - - If you are using TinyMCE 4.x then ``FEINCMS_RICHTEXT_INIT_TEMPLATE`` - needs to be set to ``admin/content/richtext/init_tinymce4.html``. - - Optionally runs the HTML code through HTML cleaners if you specify - ``cleanse=True`` when calling ``create_content_type``. - """ - - feincms_item_editor_context_processors = ( - lambda x: settings.FEINCMS_RICHTEXT_INIT_CONTEXT, - ) - feincms_item_editor_includes = { - 'head': [settings.FEINCMS_RICHTEXT_INIT_TEMPLATE], - } - - class Meta: - abstract = True - verbose_name = _('rich text') - verbose_name_plural = _('rich texts') - - def render(self, **kwargs): - return render_to_string( - 'content/richtext/default.html', - {'content': self}, - context_instance=kwargs.get('context')) - - @classmethod - def initialize_type(cls, cleanse=None): - cls.add_to_class( - 'text', - RichTextField(_('text'), blank=True, cleanse=cleanse), - ) - - -class TemplateContent(models.Model): - """ - Pass a list of templates when creating this content type. It uses the - default template system:: - - Page.create_content_type(TemplateContent, TEMPLATES=[ - ('content/template/something1.html', 'something'), - ('content/template/something2.html', 'something else'), - ('base.html', 'makes no sense'), - ]) - """ - class Meta: - abstract = True - verbose_name = _('template content') - verbose_name_plural = _('template contents') - - @classmethod - def initialize_type(cls, TEMPLATES): - cls.add_to_class('template', models.CharField( - _('template'), - max_length=100, - choices=TEMPLATES, - )) - - def render(self, **kwargs): - return render_to_string( - self.template, - {'content': self}, - context_instance=kwargs.get('context')) - - -try: - from filer.fields.file import FilerFileField - from filer.fields.image import FilerImageField -except ImportError: - pass -else: - - class MediaFileContentInline(FeinCMSInline): - radio_fields = {'type': admin.VERTICAL} - - class ContentWithFilerFile(models.Model): - """ - File content - """ - feincms_item_editor_inline = MediaFileContentInline - - class Meta: - abstract = True - - def render(self, **kwargs): - ctx = {'content': self} - ctx.update(kwargs) - return render_to_string([ - 'content/filer/%s_%s.html' % (self.file_type, self.type), - 'content/filer/%s.html' % self.type, - 'content/filer/%s.html' % self.file_type, - 'content/filer/default.html', - ], ctx, context_instance=kwargs.get('context')) - - class FilerFileContent(ContentWithFilerFile): - mediafile = FilerFileField(verbose_name=_('file'), related_name='+') - file_type = 'file' - type = 'download' - - class Meta: - abstract = True - verbose_name = _('file') - verbose_name_plural = _('files') - - class FilerImageContent(ContentWithFilerFile): - """ - Create a media file content as follows:: - - from feincms.contents import FilerImageContent - Page.create_content_type(FilerImageContent, TYPE_CHOICES=( - ('inline', _('Default')), - ('lightbox', _('Lightbox')), - ('whatever', _('Whatever')), - )) - - For a media file of type 'image' and type 'lightbox', the following - templates are tried in order: - - * content/mediafile/image_lightbox.html - * content/mediafile/lightbox.html - * content/mediafile/image.html - * content/mediafile/default.html - - The context contains ``content`` and ``request`` (if available). - - The content.mediafile attribute are as follows (selection): - label, description, default_caption, default_alt_text, - author, must_always_publish_author_credit, - must_always_publish_copyright, date_taken, file, id, is_public, url - """ - - mediafile = FilerImageField(verbose_name=_('image'), related_name='+') - caption = models.CharField( - _('caption'), - max_length=1000, - blank=True, - ) - url = models.CharField( - _('URL'), - max_length=1000, - blank=True, - ) - - file_type = 'image' - - class Meta: - abstract = True - verbose_name = _('image') - verbose_name_plural = _('images') - - @classmethod - def initialize_type(cls, TYPE_CHOICES=None): - if TYPE_CHOICES is None: - raise ImproperlyConfigured( - 'You have to set TYPE_CHOICES when' - ' creating a %s' % cls.__name__) - - cls.add_to_class( - 'type', - models.CharField( - _('type'), - max_length=20, - choices=TYPE_CHOICES, - default=TYPE_CHOICES[0][0], - ), - ) +from feincms.content.filer.models import * # noqa +from feincms.content.raw.models import RawContent # noqa +from feincms.content.richtext.models import RichTextContent # noqa +from feincms.content.template.models import TemplateContent # noqa From 487eebe0aff84a5cb9d2fa27805d04991d9def92 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Feb 2016 14:41:55 +0100 Subject: [PATCH 1297/1590] Move application content back as well... --- feincms/apps.py | 3 + feincms/apps/__init__.py | 53 ---- feincms/apps/contents.py | 300 ------------------ feincms/apps/reverse.py | 98 ------ feincms/content/application/models.py | 441 +++++++++++++++++++++++++- 5 files changed, 438 insertions(+), 457 deletions(-) create mode 100644 feincms/apps.py delete mode 100644 feincms/apps/__init__.py delete mode 100644 feincms/apps/contents.py delete mode 100644 feincms/apps/reverse.py diff --git a/feincms/apps.py b/feincms/apps.py new file mode 100644 index 000000000..fa5e7ac8c --- /dev/null +++ b/feincms/apps.py @@ -0,0 +1,3 @@ +# flake8: noqa + +from feincms.content.application.models import * diff --git a/feincms/apps/__init__.py b/feincms/apps/__init__.py deleted file mode 100644 index 367587f94..000000000 --- a/feincms/apps/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -from __future__ import absolute_import - -from functools import wraps - -from django.http import HttpResponse -from django.template.response import TemplateResponse - -from .contents import ApplicationContent -from .reverse import app_reverse, app_reverse_lazy, permalink - - -__all__ = ( - 'ApplicationContent', - 'app_reverse', 'app_reverse_lazy', 'permalink', - 'UnpackTemplateResponse', 'standalone', 'unpack', -) - - -class UnpackTemplateResponse(TemplateResponse): - """ - Completely the same as marking applicationcontent-contained views with - the ``feincms.views.decorators.unpack`` decorator. - """ - _feincms_unpack = True - - -def standalone(view_func): - """ - Marks the view method as standalone view; this means that - ``HttpResponse`` objects returned from ``ApplicationContent`` - are returned directly, without further processing. - """ - - def inner(request, *args, **kwargs): - response = view_func(request, *args, **kwargs) - if isinstance(response, HttpResponse): - response.standalone = True - return response - return wraps(view_func)(inner) - - -def unpack(view_func): - """ - Marks the returned response as to-be-unpacked if it is a - ``TemplateResponse``. - """ - - def inner(request, *args, **kwargs): - response = view_func(request, *args, **kwargs) - if isinstance(response, TemplateResponse): - response._feincms_unpack = True - return response - return wraps(view_func)(inner) diff --git a/feincms/apps/contents.py b/feincms/apps/contents.py deleted file mode 100644 index 7e95a62b8..000000000 --- a/feincms/apps/contents.py +++ /dev/null @@ -1,300 +0,0 @@ -from __future__ import absolute_import, unicode_literals - -from email.utils import parsedate -from functools import partial -from time import mktime - -from django.conf import settings -from django.core.urlresolvers import Resolver404, resolve -from django.db import models -from django.http import HttpResponse -from django.utils.http import http_date -from django.utils.safestring import mark_safe -from django.utils.translation import get_language, ugettext_lazy as _ - -from feincms.admin.item_editor import ItemEditorForm -from feincms.contrib.fields import JSONField -from feincms.translations import short_language_code -from feincms.utils import get_object - - -class ApplicationContent(models.Model): - #: parameters is used to serialize instance-specific data which will be - # provided to the view code. This allows customization (e.g. "Embed - # MyBlogApp for blog ") - parameters = JSONField(null=True, editable=False) - - ALL_APPS_CONFIG = {} - - class Meta: - abstract = True - verbose_name = _('application content') - verbose_name_plural = _('application contents') - - @classmethod - def initialize_type(cls, APPLICATIONS): - for i in APPLICATIONS: - if not 2 <= len(i) <= 3: - raise ValueError( - "APPLICATIONS must be provided with tuples containing at" - " least two parameters (urls, name) and an optional extra" - " config dict") - - urls, name = i[0:2] - - if len(i) == 3: - app_conf = i[2] - - if not isinstance(app_conf, dict): - raise ValueError( - "The third parameter of an APPLICATIONS entry must be" - " a dict or the name of one!") - else: - app_conf = {} - - cls.ALL_APPS_CONFIG[urls] = { - "urls": urls, - "name": name, - "config": app_conf - } - - cls.add_to_class( - 'urlconf_path', - models.CharField(_('application'), max_length=100, choices=[ - (c['urls'], c['name']) for c in cls.ALL_APPS_CONFIG.values()]) - ) - - class ApplicationContentItemEditorForm(ItemEditorForm): - app_config = {} - custom_fields = {} - - def __init__(self, *args, **kwargs): - super(ApplicationContentItemEditorForm, self).__init__( - *args, **kwargs) - - instance = kwargs.get("instance", None) - - if instance: - try: - # TODO use urlconf_path from POST if set - # urlconf_path = request.POST.get('...urlconf_path', - # instance.urlconf_path) - self.app_config = cls.ALL_APPS_CONFIG[ - instance.urlconf_path]['config'] - except KeyError: - self.app_config = {} - - self.custom_fields = {} - admin_fields = self.app_config.get('admin_fields', {}) - - if isinstance(admin_fields, dict): - self.custom_fields.update(admin_fields) - else: - get_fields = get_object(admin_fields) - self.custom_fields.update( - get_fields(self, *args, **kwargs)) - - params = self.instance.parameters - for k, v in self.custom_fields.items(): - v.initial = params.get(k) - self.fields[k] = v - if k in params: - self.fields[k].initial = params[k] - - def save(self, commit=True, *args, **kwargs): - # Django ModelForms return the model instance from save. We'll - # call save with commit=False first to do any necessary work & - # get the model so we can set .parameters to the values of our - # custom fields before calling save(commit=True) - - m = super(ApplicationContentItemEditorForm, self).save( - commit=False, *args, **kwargs) - - m.parameters = dict( - (k, self.cleaned_data[k]) - for k in self.custom_fields if k in self.cleaned_data) - - if commit: - m.save(**kwargs) - - return m - - # This provides hooks for us to customize the admin interface for - # embedded instances: - cls.feincms_item_editor_form = ApplicationContentItemEditorForm - - def __init__(self, *args, **kwargs): - super(ApplicationContent, self).__init__(*args, **kwargs) - self.app_config = self.ALL_APPS_CONFIG.get( - self.urlconf_path, {}).get('config', {}) - - def process(self, request, **kw): - page_url = self.parent.get_absolute_url() - - # Provide a way for appcontent items to customize URL processing by - # altering the perceived path of the page: - if "path_mapper" in self.app_config: - path_mapper = get_object(self.app_config["path_mapper"]) - path, page_url = path_mapper( - request.path, - page_url, - appcontent_parameters=self.parameters - ) - else: - path = request._feincms_extra_context['extra_path'] - - # Resolve the module holding the application urls. - urlconf_path = self.app_config.get('urls', self.urlconf_path) - - try: - fn, args, kwargs = resolve(path, urlconf_path) - except (ValueError, Resolver404): - raise Resolver404(str('Not found (resolving %r in %r failed)') % ( - path, urlconf_path)) - - # Variables from the ApplicationContent parameters are added to request - # so we can expose them to our templates via the appcontent_parameters - # context_processor - request._feincms_extra_context.update(self.parameters) - - # Save the application configuration for reuse elsewhere - request._feincms_extra_context.update({ - 'app_config': dict( - self.app_config, - urlconf_path=self.urlconf_path, - ), - }) - - view_wrapper = self.app_config.get("view_wrapper", None) - if view_wrapper: - fn = partial( - get_object(view_wrapper), - view=fn, - appcontent_parameters=self.parameters - ) - - output = fn(request, *args, **kwargs) - - if isinstance(output, HttpResponse): - if self.send_directly(request, output): - return output - elif output.status_code == 200: - - if self.unpack(request, output) and 'view' in kw: - # Handling of @unpack and UnpackTemplateResponse - kw['view'].template_name = output.template_name - kw['view'].request._feincms_extra_context.update( - output.context_data) - - else: - # If the response supports deferred rendering, render the - # response right now. We do not handle template response - # middleware. - if hasattr(output, 'render') and callable(output.render): - output.render() - - self.rendered_result = mark_safe( - output.content.decode('utf-8')) - - self.rendered_headers = {} - - # Copy relevant headers for later perusal - for h in ('Cache-Control', 'Last-Modified', 'Expires'): - if h in output: - self.rendered_headers.setdefault( - h, []).append(output[h]) - - elif isinstance(output, tuple) and 'view' in kw: - kw['view'].template_name = output[0] - kw['view'].request._feincms_extra_context.update(output[1]) - - else: - self.rendered_result = mark_safe(output) - - return True # successful - - def send_directly(self, request, response): - mimetype = response.get('Content-Type', 'text/plain') - if ';' in mimetype: - mimetype = mimetype.split(';')[0] - mimetype = mimetype.strip() - - return ( - response.status_code != 200 or - request.is_ajax() or - getattr(response, 'standalone', False) or - mimetype not in ('text/html', 'text/plain')) - - def unpack(self, request, response): - return getattr(response, '_feincms_unpack', False) - - def render(self, **kwargs): - return getattr(self, 'rendered_result', '') - - def finalize(self, request, response): - headers = getattr(self, 'rendered_headers', None) - if headers: - self._update_response_headers(request, response, headers) - - def _update_response_headers(self, request, response, headers): - """ - Combine all headers that were set by the different content types - We are interested in Cache-Control, Last-Modified, Expires - """ - - # Ideally, for the Cache-Control header, we'd want to do some - # intelligent combining, but that's hard. Let's just collect and unique - # them and let the client worry about that. - cc_headers = set(('must-revalidate',)) - for x in (cc.split(",") for cc in headers.get('Cache-Control', ())): - cc_headers |= set((s.strip() for s in x)) - - if len(cc_headers): - response['Cache-Control'] = ", ".join(cc_headers) - else: # Default value - response['Cache-Control'] = 'no-cache, must-revalidate' - - # Check all Last-Modified headers, choose the latest one - lm_list = [parsedate(x) for x in headers.get('Last-Modified', ())] - if len(lm_list) > 0: - response['Last-Modified'] = http_date(mktime(max(lm_list))) - - # Check all Expires headers, choose the earliest one - lm_list = [parsedate(x) for x in headers.get('Expires', ())] - if len(lm_list) > 0: - response['Expires'] = http_date(mktime(min(lm_list))) - - @classmethod - def app_reverse_cache_key(self, urlconf_path, **kwargs): - return 'FEINCMS:%s:APPCONTENT:%s:%s' % ( - getattr(settings, 'SITE_ID', 0), - get_language(), - urlconf_path, - ) - - @classmethod - def closest_match(cls, urlconf_path): - page_class = cls.parent.field.rel.to - - contents = cls.objects.filter( - parent__in=page_class.objects.active(), - urlconf_path=urlconf_path, - ).order_by('pk').select_related('parent') - - if len(contents) > 1: - try: - current = short_language_code(get_language()) - return [ - content for content in contents if - short_language_code(content.parent.language) == current - ][0] - - except (AttributeError, IndexError): - pass - - try: - return contents[0] - except IndexError: - pass - - return None diff --git a/feincms/apps/reverse.py b/feincms/apps/reverse.py deleted file mode 100644 index 26ee8cade..000000000 --- a/feincms/apps/reverse.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import absolute_import, unicode_literals - -from functools import wraps - -from django.core.cache import cache -from django.core.urlresolvers import ( - NoReverseMatch, reverse, get_script_prefix, set_script_prefix -) -from django.utils.functional import lazy - - -APP_REVERSE_CACHE_TIMEOUT = 3 - - -def app_reverse(viewname, urlconf=None, args=None, kwargs=None, - *vargs, **vkwargs): - """ - Reverse URLs from application contents - - Works almost like Django's own reverse() method except that it resolves - URLs from application contents. The second argument, ``urlconf``, has to - correspond to the URLconf parameter passed in the ``APPLICATIONS`` list - to ``Page.create_content_type``:: - - app_reverse('mymodel-detail', 'myapp.urls', args=...) - - or - - app_reverse('mymodel-detail', 'myapp.urls', kwargs=...) - - The second argument may also be a request object if you want to reverse - an URL belonging to the current application content. - """ - - # First parameter might be a request instead of an urlconf path, so - # we'll try to be helpful and extract the current urlconf from it - extra_context = getattr(urlconf, '_feincms_extra_context', {}) - appconfig = extra_context.get('app_config', {}) - urlconf = appconfig.get('urlconf_path', urlconf) - - from .contents import ApplicationContent - appcontent_class = ApplicationContent._feincms_content_models[0] - cache_key = appcontent_class.app_reverse_cache_key(urlconf) - url_prefix = cache.get(cache_key) - - if url_prefix is None: - content = appcontent_class.closest_match(urlconf) - - if content is not None: - if urlconf in appcontent_class.ALL_APPS_CONFIG: - # We have an overridden URLconf - app_config = appcontent_class.ALL_APPS_CONFIG[urlconf] - urlconf = app_config['config'].get('urls', urlconf) - - prefix = content.parent.get_absolute_url() - prefix += '/' if prefix[-1] != '/' else '' - - url_prefix = (urlconf, prefix) - cache.set(cache_key, url_prefix, timeout=APP_REVERSE_CACHE_TIMEOUT) - - if url_prefix: - # vargs and vkwargs are used to send through additional parameters - # which are uninteresting to us (such as current_app) - prefix = get_script_prefix() - try: - set_script_prefix(url_prefix[1]) - return reverse( - viewname, - url_prefix[0], - args=args, - kwargs=kwargs, - *vargs, **vkwargs) - finally: - set_script_prefix(prefix) - - raise NoReverseMatch("Unable to find ApplicationContent for %r" % urlconf) - - -#: Lazy version of ``app_reverse`` -app_reverse_lazy = lazy(app_reverse, str) - - -def permalink(func): - """ - Decorator that calls app_reverse() - - Use this instead of standard django.db.models.permalink if you want to - integrate the model through ApplicationContent. The wrapped function - must return 4 instead of 3 arguments:: - - class MyModel(models.Model): - @appmodels.permalink - def get_absolute_url(self): - return ('myapp.urls', 'model_detail', (), {'slug': self.slug}) - """ - def inner(*args, **kwargs): - return app_reverse(*func(*args, **kwargs)) - return wraps(func)(inner) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 854ab307b..4f3a215a1 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -1,13 +1,75 @@ -# flake8: noqa -from __future__ import absolute_import, unicode_literals +from __future__ import absolute_import +from email.utils import parsedate +from functools import partial, wraps +from time import mktime import warnings -from feincms.apps import * +from django.conf import settings +from django.core.cache import cache +from django.core.urlresolvers import ( + NoReverseMatch, reverse, get_script_prefix, set_script_prefix, + Resolver404, resolve, +) +from django.db import models +from django.http import HttpResponse +from django.template.response import TemplateResponse +from django.utils.functional import lazy +from django.utils.http import http_date +from django.utils.safestring import mark_safe +from django.utils.translation import get_language, ugettext_lazy as _ -warnings.warn( - 'Import ApplicationContent and friends from feincms.apps.', - DeprecationWarning, stacklevel=2) +from feincms.admin.item_editor import ItemEditorForm +from feincms.contrib.fields import JSONField +from feincms.translations import short_language_code +from feincms.utils import get_object + + +APP_REVERSE_CACHE_TIMEOUT = 3 + + +__all__ = ( + 'ApplicationContent', + 'app_reverse', 'app_reverse_lazy', 'permalink', + 'UnpackTemplateResponse', 'standalone', 'unpack', +) + + +class UnpackTemplateResponse(TemplateResponse): + """ + Completely the same as marking applicationcontent-contained views with + the ``feincms.views.decorators.unpack`` decorator. + """ + _feincms_unpack = True + + +def standalone(view_func): + """ + Marks the view method as standalone view; this means that + ``HttpResponse`` objects returned from ``ApplicationContent`` + are returned directly, without further processing. + """ + + def inner(request, *args, **kwargs): + response = view_func(request, *args, **kwargs) + if isinstance(response, HttpResponse): + response.standalone = True + return response + return wraps(view_func)(inner) + + +def unpack(view_func): + """ + Marks the returned response as to-be-unpacked if it is a + ``TemplateResponse``. + """ + + def inner(request, *args, **kwargs): + response = view_func(request, *args, **kwargs) + if isinstance(response, TemplateResponse): + response._feincms_unpack = True + return response + return wraps(view_func)(inner) def cycle_app_reverse_cache(*args, **kwargs): @@ -16,3 +78,370 @@ def cycle_app_reverse_cache(*args, **kwargs): ' a future version of FeinCMS.', DeprecationWarning, stacklevel=2, ) + + +def app_reverse(viewname, urlconf=None, args=None, kwargs=None, + *vargs, **vkwargs): + """ + Reverse URLs from application contents + + Works almost like Django's own reverse() method except that it resolves + URLs from application contents. The second argument, ``urlconf``, has to + correspond to the URLconf parameter passed in the ``APPLICATIONS`` list + to ``Page.create_content_type``:: + + app_reverse('mymodel-detail', 'myapp.urls', args=...) + + or + + app_reverse('mymodel-detail', 'myapp.urls', kwargs=...) + + The second argument may also be a request object if you want to reverse + an URL belonging to the current application content. + """ + + # First parameter might be a request instead of an urlconf path, so + # we'll try to be helpful and extract the current urlconf from it + extra_context = getattr(urlconf, '_feincms_extra_context', {}) + appconfig = extra_context.get('app_config', {}) + urlconf = appconfig.get('urlconf_path', urlconf) + + appcontent_class = ApplicationContent._feincms_content_models[0] + cache_key = appcontent_class.app_reverse_cache_key(urlconf) + url_prefix = cache.get(cache_key) + + if url_prefix is None: + content = appcontent_class.closest_match(urlconf) + + if content is not None: + if urlconf in appcontent_class.ALL_APPS_CONFIG: + # We have an overridden URLconf + app_config = appcontent_class.ALL_APPS_CONFIG[urlconf] + urlconf = app_config['config'].get('urls', urlconf) + + prefix = content.parent.get_absolute_url() + prefix += '/' if prefix[-1] != '/' else '' + + url_prefix = (urlconf, prefix) + cache.set(cache_key, url_prefix, timeout=APP_REVERSE_CACHE_TIMEOUT) + + if url_prefix: + # vargs and vkwargs are used to send through additional parameters + # which are uninteresting to us (such as current_app) + prefix = get_script_prefix() + try: + set_script_prefix(url_prefix[1]) + return reverse( + viewname, + url_prefix[0], + args=args, + kwargs=kwargs, + *vargs, **vkwargs) + finally: + set_script_prefix(prefix) + + raise NoReverseMatch("Unable to find ApplicationContent for %r" % urlconf) + + +#: Lazy version of ``app_reverse`` +app_reverse_lazy = lazy(app_reverse, str) + + +def permalink(func): + """ + Decorator that calls app_reverse() + + Use this instead of standard django.db.models.permalink if you want to + integrate the model through ApplicationContent. The wrapped function + must return 4 instead of 3 arguments:: + + class MyModel(models.Model): + @appmodels.permalink + def get_absolute_url(self): + return ('myapp.urls', 'model_detail', (), {'slug': self.slug}) + """ + def inner(*args, **kwargs): + return app_reverse(*func(*args, **kwargs)) + return wraps(func)(inner) + + +class ApplicationContent(models.Model): + #: parameters is used to serialize instance-specific data which will be + # provided to the view code. This allows customization (e.g. "Embed + # MyBlogApp for blog ") + parameters = JSONField(null=True, editable=False) + + ALL_APPS_CONFIG = {} + + class Meta: + abstract = True + verbose_name = _('application content') + verbose_name_plural = _('application contents') + + @classmethod + def initialize_type(cls, APPLICATIONS): + for i in APPLICATIONS: + if not 2 <= len(i) <= 3: + raise ValueError( + "APPLICATIONS must be provided with tuples containing at" + " least two parameters (urls, name) and an optional extra" + " config dict") + + urls, name = i[0:2] + + if len(i) == 3: + app_conf = i[2] + + if not isinstance(app_conf, dict): + raise ValueError( + "The third parameter of an APPLICATIONS entry must be" + " a dict or the name of one!") + else: + app_conf = {} + + cls.ALL_APPS_CONFIG[urls] = { + "urls": urls, + "name": name, + "config": app_conf + } + + cls.add_to_class( + 'urlconf_path', + models.CharField(_('application'), max_length=100, choices=[ + (c['urls'], c['name']) for c in cls.ALL_APPS_CONFIG.values()]) + ) + + class ApplicationContentItemEditorForm(ItemEditorForm): + app_config = {} + custom_fields = {} + + def __init__(self, *args, **kwargs): + super(ApplicationContentItemEditorForm, self).__init__( + *args, **kwargs) + + instance = kwargs.get("instance", None) + + if instance: + try: + # TODO use urlconf_path from POST if set + # urlconf_path = request.POST.get('...urlconf_path', + # instance.urlconf_path) + self.app_config = cls.ALL_APPS_CONFIG[ + instance.urlconf_path]['config'] + except KeyError: + self.app_config = {} + + self.custom_fields = {} + admin_fields = self.app_config.get('admin_fields', {}) + + if isinstance(admin_fields, dict): + self.custom_fields.update(admin_fields) + else: + get_fields = get_object(admin_fields) + self.custom_fields.update( + get_fields(self, *args, **kwargs)) + + params = self.instance.parameters + for k, v in self.custom_fields.items(): + v.initial = params.get(k) + self.fields[k] = v + if k in params: + self.fields[k].initial = params[k] + + def save(self, commit=True, *args, **kwargs): + # Django ModelForms return the model instance from save. We'll + # call save with commit=False first to do any necessary work & + # get the model so we can set .parameters to the values of our + # custom fields before calling save(commit=True) + + m = super(ApplicationContentItemEditorForm, self).save( + commit=False, *args, **kwargs) + + m.parameters = dict( + (k, self.cleaned_data[k]) + for k in self.custom_fields if k in self.cleaned_data) + + if commit: + m.save(**kwargs) + + return m + + # This provides hooks for us to customize the admin interface for + # embedded instances: + cls.feincms_item_editor_form = ApplicationContentItemEditorForm + + def __init__(self, *args, **kwargs): + super(ApplicationContent, self).__init__(*args, **kwargs) + self.app_config = self.ALL_APPS_CONFIG.get( + self.urlconf_path, {}).get('config', {}) + + def process(self, request, **kw): + page_url = self.parent.get_absolute_url() + + # Provide a way for appcontent items to customize URL processing by + # altering the perceived path of the page: + if "path_mapper" in self.app_config: + path_mapper = get_object(self.app_config["path_mapper"]) + path, page_url = path_mapper( + request.path, + page_url, + appcontent_parameters=self.parameters + ) + else: + path = request._feincms_extra_context['extra_path'] + + # Resolve the module holding the application urls. + urlconf_path = self.app_config.get('urls', self.urlconf_path) + + try: + fn, args, kwargs = resolve(path, urlconf_path) + except (ValueError, Resolver404): + raise Resolver404(str('Not found (resolving %r in %r failed)') % ( + path, urlconf_path)) + + # Variables from the ApplicationContent parameters are added to request + # so we can expose them to our templates via the appcontent_parameters + # context_processor + request._feincms_extra_context.update(self.parameters) + + # Save the application configuration for reuse elsewhere + request._feincms_extra_context.update({ + 'app_config': dict( + self.app_config, + urlconf_path=self.urlconf_path, + ), + }) + + view_wrapper = self.app_config.get("view_wrapper", None) + if view_wrapper: + fn = partial( + get_object(view_wrapper), + view=fn, + appcontent_parameters=self.parameters + ) + + output = fn(request, *args, **kwargs) + + if isinstance(output, HttpResponse): + if self.send_directly(request, output): + return output + elif output.status_code == 200: + + if self.unpack(request, output) and 'view' in kw: + # Handling of @unpack and UnpackTemplateResponse + kw['view'].template_name = output.template_name + kw['view'].request._feincms_extra_context.update( + output.context_data) + + else: + # If the response supports deferred rendering, render the + # response right now. We do not handle template response + # middleware. + if hasattr(output, 'render') and callable(output.render): + output.render() + + self.rendered_result = mark_safe( + output.content.decode('utf-8')) + + self.rendered_headers = {} + + # Copy relevant headers for later perusal + for h in ('Cache-Control', 'Last-Modified', 'Expires'): + if h in output: + self.rendered_headers.setdefault( + h, []).append(output[h]) + + elif isinstance(output, tuple) and 'view' in kw: + kw['view'].template_name = output[0] + kw['view'].request._feincms_extra_context.update(output[1]) + + else: + self.rendered_result = mark_safe(output) + + return True # successful + + def send_directly(self, request, response): + mimetype = response.get('Content-Type', 'text/plain') + if ';' in mimetype: + mimetype = mimetype.split(';')[0] + mimetype = mimetype.strip() + + return ( + response.status_code != 200 or + request.is_ajax() or + getattr(response, 'standalone', False) or + mimetype not in ('text/html', 'text/plain')) + + def unpack(self, request, response): + return getattr(response, '_feincms_unpack', False) + + def render(self, **kwargs): + return getattr(self, 'rendered_result', '') + + def finalize(self, request, response): + headers = getattr(self, 'rendered_headers', None) + if headers: + self._update_response_headers(request, response, headers) + + def _update_response_headers(self, request, response, headers): + """ + Combine all headers that were set by the different content types + We are interested in Cache-Control, Last-Modified, Expires + """ + + # Ideally, for the Cache-Control header, we'd want to do some + # intelligent combining, but that's hard. Let's just collect and unique + # them and let the client worry about that. + cc_headers = set(('must-revalidate',)) + for x in (cc.split(",") for cc in headers.get('Cache-Control', ())): + cc_headers |= set((s.strip() for s in x)) + + if len(cc_headers): + response['Cache-Control'] = ", ".join(cc_headers) + else: # Default value + response['Cache-Control'] = 'no-cache, must-revalidate' + + # Check all Last-Modified headers, choose the latest one + lm_list = [parsedate(x) for x in headers.get('Last-Modified', ())] + if len(lm_list) > 0: + response['Last-Modified'] = http_date(mktime(max(lm_list))) + + # Check all Expires headers, choose the earliest one + lm_list = [parsedate(x) for x in headers.get('Expires', ())] + if len(lm_list) > 0: + response['Expires'] = http_date(mktime(min(lm_list))) + + @classmethod + def app_reverse_cache_key(self, urlconf_path, **kwargs): + return 'FEINCMS:%s:APPCONTENT:%s:%s' % ( + getattr(settings, 'SITE_ID', 0), + get_language(), + urlconf_path, + ) + + @classmethod + def closest_match(cls, urlconf_path): + page_class = cls.parent.field.rel.to + + contents = cls.objects.filter( + parent__in=page_class.objects.active(), + urlconf_path=urlconf_path, + ).order_by('pk').select_related('parent') + + if len(contents) > 1: + try: + current = short_language_code(get_language()) + return [ + content for content in contents if + short_language_code(content.parent.language) == current + ][0] + + except (AttributeError, IndexError): + pass + + try: + return contents[0] + except IndexError: + pass + + return None From f2a78e4c0cd97f3a1547b1b243ee0436981ed6db Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 9 Feb 2016 12:07:57 +0100 Subject: [PATCH 1298/1590] Adjust dev status on .pre versions too --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 5ea12b61c..fc93aaf78 100755 --- a/setup.py +++ b/setup.py @@ -14,6 +14,8 @@ def read(filename): devstatus = 'Development Status :: 5 - Production/Stable' if '.dev' in version: devstatus = 'Development Status :: 3 - Alpha' +else if '.pre' in version: + devstatus = 'Development Status :: 4 - Beta' setup( name='FeinCMS', From 4e23fc9bd6601d58af1cd175f6f3e67daa64eb26 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 9 Feb 2016 12:31:26 +0100 Subject: [PATCH 1299/1590] Back out old change that came back in 9d8ee30cf712b7757784c8d518f8f2d76e5f6c5a to haunt us --- feincms/__init__.py | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 1dbac4f5b..0426f87a7 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 11, 5, 'dev') +VERSION = (1, 12, 0, 'pre') __version__ = '.'.join(map(str, VERSION)) @@ -44,14 +44,9 @@ def ensure_completely_loaded(force=False): if COMPLETELY_LOADED and not force: return True - try: - from django.apps import apps - except ImportError: - from django.db.models import loading as apps - else: - # Django 1.7 and up - if not apps.ready: - return + from django.apps import apps + if not apps.ready: + return # Ensure meta information concerning related fields is up-to-date. # Upon accessing the related fields information from Model._meta, @@ -65,8 +60,7 @@ def ensure_completely_loaded(force=False): import django if django.get_version() < '1.8': - from feincms._internal import get_models - for model in get_models(): + for model in apps.get_models(): for cache_name in ( '_field_cache', '_field_name_cache', '_m2m_cache', '_related_objects_cache', '_related_many_to_many_cache', @@ -89,15 +83,9 @@ def ensure_completely_loaded(force=False): # on a model validation error (Django 1.4 doesn't exhibit this # problem). See Issue #323 on github. if hasattr(apps, 'cache'): - try: - apps.cache.get_models.cache_clear() # Django 1.7+ - except AttributeError: - apps.cache._get_models_cache.clear() # Django 1.6- - - if hasattr(apps, 'ready'): - if apps.ready: - COMPLETELY_LOADED = True - elif apps.app_cache_ready(): - COMPLETELY_LOADED = True + apps.cache.get_models.cache_clear() + + if apps.ready: + COMPLETELY_LOADED = True return True From 3bf8f18e60dd163c79b884a61815f12e12eba5ed Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 11 Feb 2016 16:25:22 +0100 Subject: [PATCH 1300/1590] Hmm --- docs/releases/1.12.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/releases/1.12.rst b/docs/releases/1.12.rst index 9650e473c..b798f039c 100644 --- a/docs/releases/1.12.rst +++ b/docs/releases/1.12.rst @@ -45,6 +45,11 @@ Also, you need to add a model migration which renames the old migrations.RenameField('TemplateContent', 'filename', 'template'), ] +Also, prepend ``content/template/`` to all values:: + + UPDATE page_page_templatecontent + SET template='content/template/' || template; + The blog module has been completely removed ============================================ From de6b943fff2ee675cc5d58110fdf776c00605f7f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 11 Feb 2016 17:11:20 +0100 Subject: [PATCH 1301/1590] Better --- docs/releases/1.12.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/releases/1.12.rst b/docs/releases/1.12.rst index b798f039c..3622d2f97 100644 --- a/docs/releases/1.12.rst +++ b/docs/releases/1.12.rst @@ -27,7 +27,8 @@ be explicitly specified when creating the content type:: ]) Also, you need to add a model migration which renames the old -``filename`` field to the new ``template`` field:: +``filename`` field to the new ``template`` field and prepends +``content/template/`` to all filenames:: # -*- coding: utf-8 -*- from __future__ import unicode_literals @@ -43,13 +44,14 @@ Also, you need to add a model migration which renames the old operations = [ migrations.RenameField('TemplateContent', 'filename', 'template'), + migrations.RunSQL( + "UPDATE page_page_templatecontent" + " SET template='content/template/' || template;", + "UPDATE page_page_templatecontent" + " SET template=REPLACE(template, 'content/template/', '');" + ), ] -Also, prepend ``content/template/`` to all values:: - - UPDATE page_page_templatecontent - SET template='content/template/' || template; - The blog module has been completely removed ============================================ From 824f2f35c9d686086f4180082241b960a3df2b24 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 11 Feb 2016 17:22:10 +0100 Subject: [PATCH 1302/1590] Huh? --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fc93aaf78..c8cdb5c0b 100755 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ def read(filename): devstatus = 'Development Status :: 5 - Production/Stable' if '.dev' in version: devstatus = 'Development Status :: 3 - Alpha' -else if '.pre' in version: +elif '.pre' in version: devstatus = 'Development Status :: 4 - Beta' setup( From 72a11fe2be2c3932171d84d65083cc07aac02069 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 14 Mar 2016 17:35:04 +0100 Subject: [PATCH 1303/1590] get_redirect_to_target might not get a request Refs 32bbfd3add6d6ffe378fc50627769e4341f38b8e --- feincms/extensions/translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/extensions/translations.py b/feincms/extensions/translations.py index ae2a95e53..628436bc0 100644 --- a/feincms/extensions/translations.py +++ b/feincms/extensions/translations.py @@ -183,7 +183,7 @@ def handle_model(self): original_get_redirect_to_target = cls.get_redirect_to_target @monkeypatch_method(cls) - def get_redirect_to_target(self, request): + def get_redirect_to_target(self, request=None): """ Find an acceptable redirect target. If this is a local link, then try to find the page this redirect references and From b0b06fc789dc4cf6acd4672e5820bcb0920ab243 Mon Sep 17 00:00:00 2001 From: saboter Date: Fri, 8 Apr 2016 10:40:37 +0200 Subject: [PATCH 1304/1590] Patterns deprecation warning fix (Django 1.10). --- feincms/urls.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/feincms/urls.py b/feincms/urls.py index c7bccb831..94c7de494 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -7,8 +7,7 @@ handler = Handler.as_view() -urlpatterns = patterns( - '', +urlpatterns = [ url(r'^$', handler, name='feincms_home'), - url(r'^(.*)/$', handler, name='feincms_handler'), -) + url(r'^(.*)/$', handler, name='feincms_handler') +] From 19c3417cea970c358f6445729baa61c58afd7e70 Mon Sep 17 00:00:00 2001 From: saboter Date: Fri, 8 Apr 2016 10:42:01 +0200 Subject: [PATCH 1305/1590] Language detection via session - fix for translation extension. --- feincms/module/extensions/translations.py | 7 ++++--- tests/testapp/tests/test_extensions.py | 24 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 1ec9ee995..a8c6dc065 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -35,6 +35,7 @@ logger = logging.getLogger(__name__) LANGUAGE_COOKIE_NAME = django_settings.LANGUAGE_COOKIE_NAME +LANGUAGE_SESSION_KEY = translation.LANGUAGE_SESSION_KEY # ------------------------------------------------------------------------ @@ -45,7 +46,7 @@ def user_has_language_set(request): site's language settings, after all, the user's decision is what counts. """ if (hasattr(request, 'session') - and request.session.get(LANGUAGE_COOKIE_NAME) is not None): + and request.session.get(LANGUAGE_SESSION_KEY) is not None): return True if LANGUAGE_COOKIE_NAME in request.COOKIES: return True @@ -87,8 +88,8 @@ def translation_set_language(request, select_language): if hasattr(request, 'session'): # User has a session, then set this language there - if select_language != request.session.get(LANGUAGE_COOKIE_NAME): - request.session[LANGUAGE_COOKIE_NAME] = select_language + if select_language != request.session.get(LANGUAGE_SESSION_KEY): + request.session[LANGUAGE_SESSION_KEY] = select_language elif request.method == 'GET' and not fallback: # No session is active. We need to set a cookie for the language # so that it persists when users change their location to somewhere diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 60ad3c05f..140d889ff 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -4,9 +4,11 @@ from django.contrib.sites.models import Site from django.template.defaultfilters import slugify -from django.test import TestCase +from django.test import TestCase, RequestFactory +from django.utils.translation import LANGUAGE_SESSION_KEY from feincms.module.page.models import Page +from feincms.module.extensions.translations import user_has_language_set, translation_set_language class TranslationTestCase(TestCase): @@ -61,3 +63,23 @@ def testPage(self): # TODO: add request tests # with translation.override('de'): + + def test_user_has_language_set(self): + factory = RequestFactory() + request = factory.get(self.page_en.get_navigation_url()) + setattr(request, 'session', dict()) + request.session[LANGUAGE_SESSION_KEY] = 'en' + self.assertEqual(user_has_language_set(request), True) + + setattr(request, 'session', dict()) + request.COOKIES['django_language'] = 'en' + self.assertEqual(user_has_language_set(request), True) + + def test_translation_set_language(self): + factory = RequestFactory() + request = factory.get(self.page_en.get_navigation_url()) + setattr(request, 'session', dict()) + translation_set_language(request, 'en') + + self.assertEqual(request.LANGUAGE_CODE, 'en') + self.assertEqual(request.session[LANGUAGE_SESSION_KEY], 'en') From 0e41e1f2c3a9a8a0f6179608fc9b67c69319398b Mon Sep 17 00:00:00 2001 From: saboter Date: Fri, 8 Apr 2016 10:57:25 +0200 Subject: [PATCH 1306/1590] More url patterns deprecation warning fixes. --- feincms/contrib/preview/urls.py | 9 ++++----- feincms/module/medialibrary/modeladmins.py | 9 ++++----- feincms/urls.py | 2 +- tests/testapp/applicationcontent_urls.py | 9 ++++----- tests/testapp/blog_urls.py | 9 ++++----- tests/testapp/urls.py | 9 ++++----- 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/feincms/contrib/preview/urls.py b/feincms/contrib/preview/urls.py index 83bc5e4d8..128c6753b 100644 --- a/feincms/contrib/preview/urls.py +++ b/feincms/contrib/preview/urls.py @@ -1,10 +1,9 @@ -from django.conf.urls import patterns, url +from django.conf.urls import url from feincms.contrib.preview.views import PreviewHandler -urlpatterns = patterns( - '', +urlpatterns = [ url(r'^(.*)/_preview/(\d+)/$', PreviewHandler.as_view(), - name='feincms_preview'), -) + name='feincms_preview') +] diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 6c701a3f2..a745e136b 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -124,18 +124,17 @@ class MediaFileAdmin(ExtensionModelAdmin): actions = [assign_category, save_as_zipfile] def get_urls(self): - from django.conf.urls import patterns, url + from django.conf.urls import url urls = super(MediaFileAdmin, self).get_urls() - my_urls = patterns( - '', + my_urls = [ url( r'^mediafile-bulk-upload/$', self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, name='mediafile_bulk_upload', - ), - ) + ) + ] return my_urls + urls diff --git a/feincms/urls.py b/feincms/urls.py index 94c7de494..b32df201e 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -1,7 +1,7 @@ # flake8: noqa from __future__ import absolute_import -from django.conf.urls import patterns, url +from django.conf.urls import url from feincms.views.cbv.views import Handler diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index 7b83b46bd..16f990da7 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -4,7 +4,7 @@ from __future__ import absolute_import, unicode_literals -from django.conf.urls import patterns, url +from django.conf.urls import url from django.http import HttpResponse, HttpResponseRedirect from django.template.loader import render_to_string from django.template.response import TemplateResponse @@ -54,8 +54,7 @@ def inheritance20_unpack(request): return response -urlpatterns = patterns( - '', +urlpatterns = [ url(r'^$', module_root, name='ac_module_root'), url(r'^args_test/([^/]+)/([^/]+)/$', args_test, name='ac_args_test'), url(r'^kwargs_test/(?P[^/]+)/(?P[^/]+)/$', args_test), @@ -66,5 +65,5 @@ def inheritance20_unpack(request): url(r'^response/$', response), url(r'^response_decorated/$', standalone(response)), url(r'^inheritance20/$', inheritance20), - url(r'^inheritance20_unpack/$', inheritance20_unpack), -) + url(r'^inheritance20_unpack/$', inheritance20_unpack) +] diff --git a/tests/testapp/blog_urls.py b/tests/testapp/blog_urls.py index 90d7ca2ce..c374da478 100644 --- a/tests/testapp/blog_urls.py +++ b/tests/testapp/blog_urls.py @@ -1,11 +1,10 @@ -from django.conf.urls import patterns, url +from django.conf.urls import url from django.views import generic from feincms.module.blog.models import Entry -urlpatterns = patterns( - '', +urlpatterns = [ url( r'^(?P\d+)/', generic.DetailView.as_view( @@ -19,5 +18,5 @@ queryset=Entry.objects.all(), ), name='blog_entry_list' - ), -) + ) +] diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index 7610a56ea..2ff78cc04 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -2,7 +2,7 @@ import os -from django.conf.urls import patterns, include, url +from django.conf.urls import include, url from django.contrib import admin from django.contrib.staticfiles.urls import staticfiles_urlpatterns @@ -13,8 +13,7 @@ admin.autodiscover() -urlpatterns = patterns( - '', +urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url( @@ -30,7 +29,7 @@ ), url(r'', include('feincms.contrib.preview.urls')), - url(r'', include('feincms.views.cbv.urls')), -) + url(r'', include('feincms.views.cbv.urls')) +] urlpatterns += staticfiles_urlpatterns() From 141e40e795e7d9d132d26f77a01925f0af24fe94 Mon Sep 17 00:00:00 2001 From: saboter Date: Fri, 8 Apr 2016 12:20:27 +0200 Subject: [PATCH 1307/1590] Translation extension LANGUAGE_SESSION_KEY related tests cleanup. --- tests/testapp/tests/test_extensions.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 140d889ff..405a96ca9 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -6,6 +6,7 @@ from django.template.defaultfilters import slugify from django.test import TestCase, RequestFactory from django.utils.translation import LANGUAGE_SESSION_KEY +from django.conf import settings as django_settings from feincms.module.page.models import Page from feincms.module.extensions.translations import user_has_language_set, translation_set_language @@ -64,18 +65,21 @@ def testPage(self): # TODO: add request tests # with translation.override('de'): - def test_user_has_language_set(self): + def test_user_has_language_set_with_session(self): factory = RequestFactory() request = factory.get(self.page_en.get_navigation_url()) setattr(request, 'session', dict()) request.session[LANGUAGE_SESSION_KEY] = 'en' self.assertEqual(user_has_language_set(request), True) - setattr(request, 'session', dict()) - request.COOKIES['django_language'] = 'en' + def test_user_has_language_set_with_cookie(self): + factory = RequestFactory() + request = factory.get(self.page_en.get_navigation_url()) + request.COOKIES[django_settings.LANGUAGE_COOKIE_NAME] = 'en' + self.assertEqual(user_has_language_set(request), True) - def test_translation_set_language(self): + def test_translation_set_language_to_session(self): factory = RequestFactory() request = factory.get(self.page_en.get_navigation_url()) setattr(request, 'session', dict()) @@ -83,3 +87,11 @@ def test_translation_set_language(self): self.assertEqual(request.LANGUAGE_CODE, 'en') self.assertEqual(request.session[LANGUAGE_SESSION_KEY], 'en') + + def test_translation_set_language_to_cookie(self): + factory = RequestFactory() + request = factory.get(self.page_en.get_navigation_url()) + response = translation_set_language(request, 'en') + + self.assertEqual(request.LANGUAGE_CODE, 'en') + self.assertEqual(response.cookies[django_settings.LANGUAGE_COOKIE_NAME].value, 'en') \ No newline at end of file From 7addc2853844841633cb56ca14b5901e1c9d137c Mon Sep 17 00:00:00 2001 From: saboter Date: Fri, 8 Apr 2016 13:00:58 +0200 Subject: [PATCH 1308/1590] Coding style fix. Added LANGUAGE_SESSION_KEY fallback for Django 1.6. --- feincms/module/extensions/translations.py | 6 +++++- tests/testapp/tests/test_extensions.py | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index a8c6dc065..092e105ad 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -35,7 +35,11 @@ logger = logging.getLogger(__name__) LANGUAGE_COOKIE_NAME = django_settings.LANGUAGE_COOKIE_NAME -LANGUAGE_SESSION_KEY = translation.LANGUAGE_SESSION_KEY +if translation.LANGUAGE_SESSION_KEY: + LANGUAGE_SESSION_KEY = translation.LANGUAGE_SESSION_KEY +else: + # Django 1.6 + LANGUAGE_SESSION_KEY = LANGUAGE_COOKIE_NAME # ------------------------------------------------------------------------ diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 405a96ca9..0ecfb0a39 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -5,11 +5,12 @@ from django.contrib.sites.models import Site from django.template.defaultfilters import slugify from django.test import TestCase, RequestFactory -from django.utils.translation import LANGUAGE_SESSION_KEY +from django.utils import translation from django.conf import settings as django_settings from feincms.module.page.models import Page -from feincms.module.extensions.translations import user_has_language_set, translation_set_language +from feincms.module.extensions.translations import user_has_language_set,\ + translation_set_language class TranslationTestCase(TestCase): @@ -35,6 +36,12 @@ def setUp(self): self.page_de = de.parent self.page_en = en.parent + if translation.LANGUAGE_SESSION_KEY: + self.language_session_key = translation.LANGUAGE_SESSION_KEY + else: + # Django 1.6 + self.language_session_key = django_settings.LANGUAGE_COOKIE_NAME + def create_page(self, title='Test page', parent=None, **kwargs): defaults = { 'template_key': 'base', @@ -69,7 +76,7 @@ def test_user_has_language_set_with_session(self): factory = RequestFactory() request = factory.get(self.page_en.get_navigation_url()) setattr(request, 'session', dict()) - request.session[LANGUAGE_SESSION_KEY] = 'en' + request.session[self.language_session_key] = 'en' self.assertEqual(user_has_language_set(request), True) def test_user_has_language_set_with_cookie(self): @@ -86,7 +93,7 @@ def test_translation_set_language_to_session(self): translation_set_language(request, 'en') self.assertEqual(request.LANGUAGE_CODE, 'en') - self.assertEqual(request.session[LANGUAGE_SESSION_KEY], 'en') + self.assertEqual(request.session[self.language_session_key], 'en') def test_translation_set_language_to_cookie(self): factory = RequestFactory() @@ -94,4 +101,4 @@ def test_translation_set_language_to_cookie(self): response = translation_set_language(request, 'en') self.assertEqual(request.LANGUAGE_CODE, 'en') - self.assertEqual(response.cookies[django_settings.LANGUAGE_COOKIE_NAME].value, 'en') \ No newline at end of file + self.assertEqual(response.cookies[django_settings.LANGUAGE_COOKIE_NAME].value, 'en') From 364e283e163332f7612454ceac486e70b610efe1 Mon Sep 17 00:00:00 2001 From: saboter Date: Fri, 8 Apr 2016 13:08:59 +0200 Subject: [PATCH 1309/1590] Flake8 warning fix. --- tests/testapp/tests/test_extensions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 0ecfb0a39..68d1179d0 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -9,8 +9,8 @@ from django.conf import settings as django_settings from feincms.module.page.models import Page -from feincms.module.extensions.translations import user_has_language_set,\ - translation_set_language +from feincms.module.extensions.translations import user_has_language_set +from feincms.module.extensions.translations import translation_set_language class TranslationTestCase(TestCase): @@ -101,4 +101,6 @@ def test_translation_set_language_to_cookie(self): response = translation_set_language(request, 'en') self.assertEqual(request.LANGUAGE_CODE, 'en') - self.assertEqual(response.cookies[django_settings.LANGUAGE_COOKIE_NAME].value, 'en') + + c_key = django_settings.LANGUAGE_COOKIE_NAME + self.assertEqual(response.cookies[c_key].value, 'en') From 7995da8f2d87f5034c7e3da30b613b6c602f9c63 Mon Sep 17 00:00:00 2001 From: saboter Date: Fri, 8 Apr 2016 13:15:21 +0200 Subject: [PATCH 1310/1590] Django 1.6 fallback for LANGUAGE_SESSION_KEY (this time, working implementation). --- feincms/module/extensions/translations.py | 2 +- tests/testapp/tests/test_extensions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 092e105ad..d74f3602c 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -35,7 +35,7 @@ logger = logging.getLogger(__name__) LANGUAGE_COOKIE_NAME = django_settings.LANGUAGE_COOKIE_NAME -if translation.LANGUAGE_SESSION_KEY: +if hasattr(translation, 'LANGUAGE_SESSION_KEY'): LANGUAGE_SESSION_KEY = translation.LANGUAGE_SESSION_KEY else: # Django 1.6 diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 68d1179d0..7815d1c27 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -36,7 +36,7 @@ def setUp(self): self.page_de = de.parent self.page_en = en.parent - if translation.LANGUAGE_SESSION_KEY: + if hasattr(translation, 'LANGUAGE_SESSION_KEY'): self.language_session_key = translation.LANGUAGE_SESSION_KEY else: # Django 1.6 From 2f170667800d28f340f720343684d78f00331b8c Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 12 Apr 2016 12:30:01 +0200 Subject: [PATCH 1311/1590] Factor out handling of "page.page:42" type strings to own functions match_model_string() and get_model_instance() in feincms.utils. This allows for other content types to also use that linking notation without reimplementing the parsing logic. --- feincms/module/page/models.py | 28 ++++------------------- feincms/utils/__init__.py | 43 ++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index d1968570c..ba3151662 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -21,13 +21,7 @@ from feincms.module.mixins import ContentModelMixin from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin - -from feincms.utils import shorten_string - - -REDIRECT_TO_RE = re.compile( - r'^(?P\w+).(?P\w+):(?P\d+)$') - +from feincms.utils import shorten_string, match_model_string, get_model_instance # ------------------------------------------------------------------------ class BasePageManager(ActiveAwareContentManagerMixin, TreeManager): @@ -336,25 +330,11 @@ def get_redirect_to_page(self): return None # It might be an identifier for a different object - match = REDIRECT_TO_RE.match(self.redirect_to) - - # It's not, oh well. - if not match: + whereto = match_model_string(self.redirect_to) + if not whereto: return None - matches = match.groupdict() - model = apps.get_model(matches['app_label'], matches['model_name']) - - if not model: - return None - - try: - instance = model._default_manager.get(pk=int(matches['pk'])) - return instance - except models.ObjectDoesNotExist: - pass - - return None + return get_model_instance(*whereto) def get_redirect_to_target(self, request=None): """ diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 48a346908..28c6b69d3 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -4,6 +4,8 @@ from __future__ import absolute_import, division, unicode_literals +import re + from importlib import import_module from django.apps import apps @@ -13,7 +15,6 @@ from feincms import settings - # ------------------------------------------------------------------------ def get_object(path, fail_silently=False): # Return early if path isn't a string (might already be an callable or @@ -33,6 +34,46 @@ def get_object(path, fail_silently=False): if not fail_silently: raise +# ------------------------------------------------------------------------ +def get_model_instance(app_label, model_name, pk): + """ + Find an object instance given an app_label, a model name and the + object's pk. + + This is used for page's get_link_target but can be used for other + content types that accept e.g. either an internal or external link. + """ + + model = apps.get_model(app_label, model_name) + if not model: + return None + + try: + instance = model._default_manager.get(pk=pk) + return instance + except model.ObjectDoesNotExist: + pass + + return None + +# ------------------------------------------------------------------------ +REDIRECT_TO_RE = re.compile( + r'^(?P\w+).(?P\w+):(?P\d+)$') + +def match_model_string(s): + """ + Try to parse a string in format "app_label.model_name:pk", as is used + Page.get_link_target() + + Returns a tuple app_label, model_name, pk or None if the string + does not match the expected format. + """ + + match = REDIRECT_TO_RE.match(s) + if not match: + return None + matches = match.groupdict() + return (matches['app_label'], matches['model_name'], int(matches['pk'])) # ------------------------------------------------------------------------ def copy_model_instance(obj, exclude=None): From a06e6cc3c0b0440d3adedd1ccce78309d8fae9a9 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 13 Apr 2016 13:13:45 +0200 Subject: [PATCH 1312/1590] Allow navigationgroup to be blank --- feincms/module/page/extensions/navigationgroups.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/module/page/extensions/navigationgroups.py b/feincms/module/page/extensions/navigationgroups.py index fb07eb582..fc47ec033 100644 --- a/feincms/module/page/extensions/navigationgroups.py +++ b/feincms/module/page/extensions/navigationgroups.py @@ -26,6 +26,7 @@ def handle_model(self): choices=self.groups, default=self.groups[0][0], max_length=20, + blank=True, db_index=True)) def handle_modeladmin(self, modeladmin): From 498ae812e338da67a0b2acfbd179779cfb39a50b Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 19 Apr 2016 10:37:11 +0200 Subject: [PATCH 1313/1590] Add on_delete=PROTECT to media file reference, so deleting a media file won't silently delete all ContentWithMediaFile. --- feincms/module/medialibrary/fields.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 09279b4f6..71d8073d9 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -69,7 +69,9 @@ class feincms_item_editor_inline(FeinCMSInline): raw_id_fields = ('mediafile',) mediafile = MediaFileForeignKey( - MediaFile, verbose_name=_('media file'), related_name='+') + MediaFile, verbose_name=_('media file'), related_name='+', + on_delete=models.PROTECT + ) class Meta: abstract = True From fa854d70bac6a5ffa6519e32c96a7fece26f869b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 27 Apr 2016 14:07:02 +0200 Subject: [PATCH 1314/1590] Add back changes lost in dirty merge --- feincms/extensions/translations.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/feincms/extensions/translations.py b/feincms/extensions/translations.py index 628436bc0..d02d31337 100644 --- a/feincms/extensions/translations.py +++ b/feincms/extensions/translations.py @@ -17,7 +17,6 @@ from __future__ import absolute_import, unicode_literals - # ------------------------------------------------------------------------ import logging @@ -34,7 +33,13 @@ # ------------------------------------------------------------------------ logger = logging.getLogger(__name__) + LANGUAGE_COOKIE_NAME = django_settings.LANGUAGE_COOKIE_NAME +if hasattr(translation, 'LANGUAGE_SESSION_KEY'): + LANGUAGE_SESSION_KEY = translation.LANGUAGE_SESSION_KEY +else: + # Django 1.6 + LANGUAGE_SESSION_KEY = LANGUAGE_COOKIE_NAME # ------------------------------------------------------------------------ @@ -44,8 +49,8 @@ def user_has_language_set(request): This is taken later on as an indication that we should not mess with the site's language settings, after all, the user's decision is what counts. """ - if (hasattr(request, 'session') and - request.session.get(LANGUAGE_COOKIE_NAME) is not None): + if (hasattr(request, 'session') + and request.session.get(LANGUAGE_SESSION_KEY) is not None): return True if LANGUAGE_COOKIE_NAME in request.COOKIES: return True @@ -87,8 +92,8 @@ def translation_set_language(request, select_language): if hasattr(request, 'session'): # User has a session, then set this language there - if select_language != request.session.get(LANGUAGE_COOKIE_NAME): - request.session[LANGUAGE_COOKIE_NAME] = select_language + if select_language != request.session.get(LANGUAGE_SESSION_KEY): + request.session[LANGUAGE_SESSION_KEY] = select_language elif request.method == 'GET' and not fallback: # No session is active. We need to set a cookie for the language # so that it persists when users change their location to somewhere From 67bb54403fd7acb8e2197ddc95850710d7829a27 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 27 Apr 2016 14:10:03 +0200 Subject: [PATCH 1315/1590] flake8 clean everything --- feincms/extensions/translations.py | 4 ++-- feincms/module/medialibrary/modeladmins.py | 1 - feincms/module/page/models.py | 8 ++++---- feincms/utils/__init__.py | 5 +++++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/feincms/extensions/translations.py b/feincms/extensions/translations.py index d02d31337..bd696320f 100644 --- a/feincms/extensions/translations.py +++ b/feincms/extensions/translations.py @@ -49,8 +49,8 @@ def user_has_language_set(request): This is taken later on as an indication that we should not mess with the site's language settings, after all, the user's decision is what counts. """ - if (hasattr(request, 'session') - and request.session.get(LANGUAGE_SESSION_KEY) is not None): + if (hasattr(request, 'session') and + request.session.get(LANGUAGE_SESSION_KEY) is not None): return True if LANGUAGE_COOKIE_NAME in request.COOKIES: return True diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 8f7b5f02d..8d58b6eb5 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -123,7 +123,6 @@ class MediaFileAdmin(ExtensionModelAdmin): def get_urls(self): from django.conf.urls import url - urls = super(MediaFileAdmin, self).get_urls() return [ url( r'^mediafile-bulk-upload/$', diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index ba3151662..933fd5822 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -4,9 +4,6 @@ from __future__ import absolute_import, unicode_literals -import re - -from django.apps import apps from django.core.exceptions import PermissionDenied from django.db import models from django.db.models import Q @@ -21,7 +18,10 @@ from feincms.module.mixins import ContentModelMixin from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin -from feincms.utils import shorten_string, match_model_string, get_model_instance +from feincms.utils import ( + shorten_string, match_model_string, get_model_instance +) + # ------------------------------------------------------------------------ class BasePageManager(ActiveAwareContentManagerMixin, TreeManager): diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index 28c6b69d3..f1a697a1e 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -15,6 +15,7 @@ from feincms import settings + # ------------------------------------------------------------------------ def get_object(path, fail_silently=False): # Return early if path isn't a string (might already be an callable or @@ -34,6 +35,7 @@ def get_object(path, fail_silently=False): if not fail_silently: raise + # ------------------------------------------------------------------------ def get_model_instance(app_label, model_name, pk): """ @@ -56,10 +58,12 @@ def get_model_instance(app_label, model_name, pk): return None + # ------------------------------------------------------------------------ REDIRECT_TO_RE = re.compile( r'^(?P\w+).(?P\w+):(?P\d+)$') + def match_model_string(s): """ Try to parse a string in format "app_label.model_name:pk", as is used @@ -75,6 +79,7 @@ def match_model_string(s): matches = match.groupdict() return (matches['app_label'], matches['model_name'], int(matches['pk'])) + # ------------------------------------------------------------------------ def copy_model_instance(obj, exclude=None): """ From 0fae5757aa976723ef7fd1e81311386ebc400c80 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 11 May 2016 14:27:08 +0200 Subject: [PATCH 1316/1590] Update the release notes --- docs/releases/1.12.rst | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/releases/1.12.rst b/docs/releases/1.12.rst index 3622d2f97..4b41d3506 100644 --- a/docs/releases/1.12.rst +++ b/docs/releases/1.12.rst @@ -6,11 +6,10 @@ Welcome to FeinCMS 1.12! .. warning:: - This is a cleanup release. Lots of changes ahead! + This is a cleanup release. Lots of changes ahead! Please report problems + in our issue tracker on Github_! - -Simplification of import paths -============================== +.. _Github: https://github.com/feincms/feincms/issues Template content requires explicit list of templates @@ -56,10 +55,18 @@ Also, you need to add a model migration which renames the old The blog module has been completely removed ============================================ +If you need a blog, have a look at Elephantblog_ instead. + +.. _Elephantblog: https://github.com/feincms/feincms-elephantblog + Caching of pages in various page manager methods has been removed ================================================================= +Some methods such as `Page.objects.for_request` automatically cached +the page instances. This behavior lead to non-obvious problems and has +therefore been removed. + Backwards-incompatible changes ============================== @@ -86,8 +93,7 @@ South is not supported anymore? Django 1.7 and better only? New deprecations ================ -* VideoContent, SectionContent, ContactForm?, old import paths -* Point 1 +* None. Notable features and improvements @@ -103,7 +109,7 @@ Notable features and improvements Bugfixes ======== -* Bug fix 1 +* Too many to list. Compatibility with Django and other apps From 776f569e53b6af445dd9194ce6cd05b14cf5a218 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 11 May 2016 14:27:51 +0200 Subject: [PATCH 1317/1590] FeinCMS v1.12.0 --- AUTHORS | 99 +++++++++++++++++++++++---------------------- feincms/__init__.py | 2 +- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/AUTHORS b/AUTHORS index 5f6987dd0..c2307127a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,103 +10,104 @@ The authors of FeinCMS are: * Bjorn Post * Julien Phalip * Daniel Renz -* Matt Dawson * Simon Schürpf -* Skylar Saveland +* Matt Dawson * Stefan Reinhard +* Skylar Saveland * Peter Schmidt * Marc Egli * Psyton * Simon Schmid * Greg Turner +* saboter * Charlie Denton -* Maarten van Gompel (proycon) * Bjarni Thorisson +* Maarten van Gompel (proycon) * Greg Taylor -* Jonas -* Urs Breton * Antoni Aloy * Julian Bez -* Vítor Figueiró -* Fabian Germann +* Urs Breton +* Jonas * Marc Tamlyn -* Martin Mahner -* Max Peterson -* Nico Echaniz +* Vítor Figueiró * Sander van Leeuwen * Toby White +* Nico Echaniz * Afonso Fernández Nogueira +* Max Peterson +* Fabian Germann +* Martin Mahner +* Eric Delord +* Andrew D. Ball * Brian Macdonald -* Torkn * Emmanuelle Delescolle -* adsworth -* Maarten Draijer * Gabriel Kovacs -* Eric Delord -* Andrew D. Ball +* Maarten Draijer +* Torkn +* adsworth +* Vaclav Klecanda * Michael Kutý -* Mikhail Korobov -* valmynd * Wil Tan +* Raphael Jasjukaitis +* Cellarosi Marco +* valmynd +* Mikhail Korobov +* Richard A * Maciek Szczesniak +* Håvard Grimelid +* Fabian Vogler * Marco Fucci * Perry Roper +* tayg * Denis Popov -* Cellarosi Marco -* Raphael Jasjukaitis -* Håvard Grimelid -* Richard A * Michael Bashkirov -* tayg -* Fabian Vogler -* Vaclav Klecanda +* Piet Delport +* Denis Martinez * Riccardo Coroneo * Richard Bolt * Rico Moorman -* svleeuwen +* David Evans * Saurabh Kumar * Sebastian Hillig * Silvan Spross +* Darryl Woods +* Daniele Procida +* Dan Büschlen * Artur Barseghyan -* Harro van der Klauw +* Anshuman Bhaduri * Andrin Heusser -* Andrey Popelo -* Andi Albrecht -* Alex Kamedov * Sumit Datta * Sun Liwen * Tobias Haffner -* Alen Mujezinovic +* Andrey Popelo +* Andi Albrecht * Valtron +* Alex Kamedov * Wim Feijen * Wouter van der Graaf * antiflu * feczo -* George Karpenkov -* Giorgos Logiotatidis -* Erik Stein -* Gwildor Sok -* Anshuman Bhaduri -* Jay Yu -* Jimmy Ye +* i-trofimtschuk +* ilmarsm +* niklaushug +* Alen Mujezinovic +* sperrygrove * Jonas Svensson -* Domas Lapinskas -* Kevin Etienne +* Jimmy Ye * Laurent Paoletti +* Kevin Etienne * Livio Lunin -* Denis Martinez -* David Evans -* i-trofimtschuk +* svleeuwen +* Jay Yu +* Harro van der Klauw * Marco Cellarosi * Mark Renton -* Darryl Woods -* ilmarsm +* Gwildor Sok +* Giorgos Logiotatidis * Mason Hugus -* Daniele Procida -* Dan Büschlen -* niklaushug +* George Karpenkov +* Erik Stein * Mikkel Hoegh -* sperrygrove +* Domas Lapinskas * Olekasnadr Gula * Paul Garner -* Piet Delport diff --git a/feincms/__init__.py b/feincms/__init__.py index 0426f87a7..959a28bce 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 12, 0, 'pre') +VERSION = (1, 12, 0) __version__ = '.'.join(map(str, VERSION)) From 30d9bd466612d79473eb883cc0d4c6528819c572 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 12 May 2016 14:05:50 +0200 Subject: [PATCH 1318/1590] Fix #630: Add feincms_parentlink back (was removed by accident) --- feincms/templatetags/feincms_page_tags.py | 15 +++++++++++++++ tests/testapp/tests/test_page.py | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index b5d590818..ae43c573a 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -494,3 +494,18 @@ def page_is_active(context, page, feincms_page=None, path=None): if feincms_page is None: feincms_page = context['feincms_page'] return page.is_ancestor_of(feincms_page, include_self=True) + + +# ------------------------------------------------------------------------ +@register.simple_tag +def feincms_parentlink(of_, feincms_page, **kwargs): + level = int(kwargs.get('level', 1)) + if feincms_page.level + 1 == level: + return feincms_page.get_absolute_url() + elif feincms_page.level + 1 < level: + return '#' + + try: + return feincms_page.get_ancestors()[level - 1].get_absolute_url() + except IndexError: + return '#' diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 52a9051b6..863424db5 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -653,6 +653,11 @@ def test_17_page_template_tags(self): context = template.Context({'feincms_page': page2, 'page3': page3}) + t = template.Template( + '{% load feincms_page_tags %}{% feincms_parentlink of feincms_page' + ' level=1 %}') + self.assertEqual(t.render(context), '/test-page/') + t = template.Template( '{% load feincms_page_tags %}{% feincms_languagelinks for' ' feincms_page as links %}{% for key, name, link in links %}' From 17edc4dbfad5e4267042ca4220d82e797592e073 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 12 May 2016 14:06:33 +0200 Subject: [PATCH 1319/1590] FeinCMS v1.12.1 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 959a28bce..899264667 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 12, 0) +VERSION = (1, 12, 1) __version__ = '.'.join(map(str, VERSION)) From 409669dee9a148e3d6bfd0bd0f5ed90942990f6d Mon Sep 17 00:00:00 2001 From: Sebastian Walter Date: Fri, 5 Aug 2016 16:21:53 +0200 Subject: [PATCH 1320/1590] partial fix to #636 (works now for Django 1.10) --- feincms/contrib/fields.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index a2f207527..a39c36a58 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -29,8 +29,7 @@ def clean(self, value, *args, **kwargs): return super(JSONFormField, self).clean(value, *args, **kwargs) - -class JSONField(six.with_metaclass(models.SubfieldBase, models.TextField)): +class JSONField(models.TextField): """ TextField which transparently serializes/unserializes JSON objects @@ -61,6 +60,9 @@ def to_python(self, value): assert value is None return {} + def from_db_value(self, value, expression, connection, context): + return self.to_python(value) + def get_prep_value(self, value): """Convert our JSON object to a string before we save""" return self._flatten_value(value) From 19d05f8d8373700ff21e5a376d4f7cdfb8971e70 Mon Sep 17 00:00:00 2001 From: Sebastian Walter Date: Fri, 5 Aug 2016 17:47:25 +0200 Subject: [PATCH 1321/1590] Problem: django.get_version() < '1.8' does not work for versions >= 1.10 Solution: use distutils.version.LooseVersion to compare version strings --- feincms/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 899264667..748a31680 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -58,7 +58,9 @@ def ensure_completely_loaded(force=False): # that relations defined after all content types registrations # don't miss out. import django - if django.get_version() < '1.8': + from distutils.version import LooseVersion + + if LooseVersion(django.get_version()) < LooseVersion('1.8'): for model in apps.get_models(): for cache_name in ( From 4260f8fd0f041e9d14cff18acda5066d208a9c2c Mon Sep 17 00:00:00 2001 From: Sebastian Walter Date: Fri, 5 Aug 2016 18:50:56 +0200 Subject: [PATCH 1322/1590] Problem: context_instance is deprecated in render_to_response Solution: store values in context --- feincms/content/contactform/models.py | 4 ++-- feincms/content/file/models.py | 5 +++-- feincms/content/filer/models.py | 2 +- feincms/content/image/models.py | 6 ++++-- feincms/content/richtext/models.py | 5 +++-- feincms/content/template/models.py | 5 +++-- feincms/content/video/models.py | 5 ++--- feincms/module/medialibrary/contents.py | 2 +- feincms/module/medialibrary/modeladmins.py | 2 +- feincms/shortcuts.py | 2 +- 10 files changed, 21 insertions(+), 17 deletions(-) diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index 35cb2f6b1..c927dbc77 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -46,7 +46,7 @@ def process(self, request, **kwargs): if request.GET.get('_cf_thanks'): self.rendered_output = render_to_string( 'content/contactform/thanks.html', - context_instance=RequestContext(request)) + request=request) return if request.method == 'POST': @@ -77,7 +77,7 @@ def process(self, request, **kwargs): 'content': self, 'form': form, }, - context_instance=RequestContext(request)) + request=request) def render(self, **kwargs): return getattr(self, 'rendered_output', '') diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index 5b86d9f95..19d362b31 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -29,11 +29,12 @@ class Meta: verbose_name_plural = _('files') def render(self, **kwargs): + context = kwargs.get('context') + context.update({'content': self}) return render_to_string( [ 'content/file/%s.html' % self.region, 'content/file/default.html', ], - {'content': self}, - context_instance=kwargs.get('context'), + context, ) diff --git a/feincms/content/filer/models.py b/feincms/content/filer/models.py index 634dd4ba7..1a63a2c59 100644 --- a/feincms/content/filer/models.py +++ b/feincms/content/filer/models.py @@ -41,7 +41,7 @@ def render(self, **kwargs): 'content/filer/%s.html' % self.type, 'content/filer/%s.html' % self.file_type, 'content/filer/default.html', - ], ctx, context_instance=kwargs.get('context')) + ], ctx) class FilerFileContent(ContentWithFilerFile): mediafile = FilerFileField(verbose_name=_('file'), related_name='+') diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index 69ff2da2d..c3f92162a 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -59,10 +59,12 @@ def render(self, **kwargs): templates = ['content/image/default.html'] if hasattr(self, 'position'): templates.insert(0, 'content/image/%s.html' % self.position) + + ctx = {'content': self} + ctx.update(kwargs) return render_to_string( templates, - {'content': self}, - context_instance=kwargs.get('context'), + ctx, ) def get_image(self): diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index e32ee4c09..94cc73ff3 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -34,10 +34,11 @@ class Meta: verbose_name_plural = _('rich texts') def render(self, **kwargs): + ctx = {'content': self} + ctx.update(kwargs) return render_to_string( 'content/richtext/default.html', - {'content': self}, - context_instance=kwargs.get('context')) + ctx) @classmethod def initialize_type(cls, cleanse=None): diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 1060e1235..506cd017e 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -33,7 +33,8 @@ def initialize_type(cls, TEMPLATES): )) def render(self, **kwargs): + ctx = {'content': self} + ctx.update(kwargs) return render_to_string( self.template, - {'content': self}, - context_instance=kwargs.get('context')) + ctx) diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index b650aa21a..3f00480dd 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -66,9 +66,8 @@ def ctx_for_video(self, vurl): return ctx def render(self, **kwargs): - context_instance = kwargs.get('context') ctx = self.ctx_for_video(self.video) + ctx.update(kwargs) return render_to_string( self.get_templates(ctx['portal']), - ctx, - context_instance=context_instance) + ctx) diff --git a/feincms/module/medialibrary/contents.py b/feincms/module/medialibrary/contents.py index 3c6bab81c..98ba6f6a2 100644 --- a/feincms/module/medialibrary/contents.py +++ b/feincms/module/medialibrary/contents.py @@ -72,4 +72,4 @@ def render(self, **kwargs): 'content/mediafile/%s.html' % self.mediafile.type, 'content/mediafile/%s.html' % self.type, 'content/mediafile/default.html', - ], ctx, context_instance=kwargs.get('context')) + ], ctx) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 8d58b6eb5..102d22674 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -78,7 +78,7 @@ class AddCategoryForm(forms.Form): 'mediafiles': queryset, 'category_form': form, 'opts': modeladmin.model._meta, - }, context_instance=RequestContext(request)) + }, request=request) assign_category.short_description = _('Add selected media files to category') diff --git a/feincms/shortcuts.py b/feincms/shortcuts.py index adb47aa4e..1f72b27db 100644 --- a/feincms/shortcuts.py +++ b/feincms/shortcuts.py @@ -17,4 +17,4 @@ def render_to_response_best_match(request, template_name, dictionary=None): return render_to_response( template_name, dictionary, - context_instance=RequestContext(request)) + request=request) From c18dd93627d1d7a3875525166acea5f4de38032e Mon Sep 17 00:00:00 2001 From: Sebastian Walter Date: Mon, 8 Aug 2016 09:48:27 +0200 Subject: [PATCH 1323/1590] Problem: feincms should be compatible with Django >= 1.8 but API has changed Solution: use django.get_version See: https://github.com/feincms/feincms/issues/636#issuecomment-238010313 --- feincms/contrib/fields.py | 10 +++++++++- tests/tox.ini | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index a39c36a58..2066133ef 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -2,7 +2,9 @@ import json import logging +from distutils.version import LooseVersion +from django import get_version from django import forms from django.db import models from django.core.serializers.json import DjangoJSONEncoder @@ -29,7 +31,13 @@ def clean(self, value, *args, **kwargs): return super(JSONFormField, self).clean(value, *args, **kwargs) -class JSONField(models.TextField): + +if LooseVersion(get_version()) > LooseVersion('1.8'): + workaround_class = models.TextField +else: + workaround_class = six.with_metaclass(models.SubfieldBase, models.TextField) + +class JSONField(workaround_class): """ TextField which transparently serializes/unserializes JSON objects diff --git a/tests/tox.ini b/tests/tox.ini index 2b7ced15e..69f4a8a20 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -5,6 +5,8 @@ envlist = {py26,py27,py32,py33,py34}-django16, {py27,py33,py34}-django17, {py27,py34}-django18, + {py27,py34}-django19 + [testenv] commands = @@ -15,6 +17,7 @@ deps = django16: Django>=1.6,<1.7 django17: Django>=1.7,<1.8 django18: Django>=1.8,<1.9 + django19: Django>=1.9,<1.10 feedparser==5.1.3 Pillow==2.4.0 pytz==2014.10 @@ -24,3 +27,4 @@ deps = {py27,py34}-django18: django-mptt==0.7.1 {py26,py27}-django{16,17,18}: BeautifulSoup==3.2.1 {py32,py33,py34}-django{16,17,18}: beautifulsoup4==4.3.1 + {py27,py34}-django{19}: django-mptt==0.8.5 From 2939d6aeae7990f3fbc45cd97273319c0c2a116d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 10:41:41 +0200 Subject: [PATCH 1324/1590] Add a test which verifies that context processor's values are available in content type's templates --- tests/testapp/context_processors.py | 2 ++ tests/testapp/settings.py | 1 + tests/testapp/templates/feincms_base.html | 1 + tests/testapp/templates/templatecontent_1.html | 1 + tests/testapp/tests/test_page.py | 18 ++++++++++++++---- 5 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/testapp/context_processors.py diff --git a/tests/testapp/context_processors.py b/tests/testapp/context_processors.py new file mode 100644 index 000000000..7d0253c20 --- /dev/null +++ b/tests/testapp/context_processors.py @@ -0,0 +1,2 @@ +def test_context(request): + return {'THE_ANSWER': 42} diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index d6e2612ac..36c764ec9 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -44,6 +44,7 @@ 'django.core.context_processors.static', # request context processor is needed 'django.core.context_processors.request', + 'testapp.context_processors.test_context', ) MIDDLEWARE_CLASSES = ( diff --git a/tests/testapp/templates/feincms_base.html b/tests/testapp/templates/feincms_base.html index 3cac88c3a..78f055f6b 100644 --- a/tests/testapp/templates/feincms_base.html +++ b/tests/testapp/templates/feincms_base.html @@ -1 +1,2 @@ +{% extends "base.html" %} {# only has to exist #} diff --git a/tests/testapp/templates/templatecontent_1.html b/tests/testapp/templates/templatecontent_1.html index f2194550e..b2986f579 100644 --- a/tests/testapp/templates/templatecontent_1.html +++ b/tests/testapp/templates/templatecontent_1.html @@ -1 +1,2 @@ TemplateContent_1 +#{{ THE_ANSWER }}# diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 863424db5..900618aca 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1659,14 +1659,14 @@ def test_40_page_is_active(self): {'feincms_page': page2}, p, path='/test-page/')) def test_41_templatecontent(self): - page = self.create_page() + page = self.create_page(active=True) template = page.templatecontent_set.create( - region=0, - ordering=1, + region='main', + ordering=10, template='templatecontent_1.html', ) - self.assertEqual(template.render(), 'TemplateContent_1\n') + self.assertEqual(template.render(), 'TemplateContent_1\n##\n') # The empty form contains the template option. self.login() @@ -1675,3 +1675,13 @@ def test_41_templatecontent(self): reverse('admin:page_page_change', args=(page.id,)) ), '') + + response = self.client.get(page.get_absolute_url()) + self.assertContains( + response, + 'TemplateContent_1', + ) + self.assertContains( + response, + '#42#', + ) From 59398ac57e4f0ea72c3d65e645533858d68a1d4e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 11:02:11 +0200 Subject: [PATCH 1325/1590] Hopefully adapt correctly to the render_to_string API change --- feincms/_internal.py | 24 ++++++++++++++++++++++ feincms/content/contactform/models.py | 8 +++++--- feincms/content/file/models.py | 10 ++++----- feincms/content/filer/models.py | 21 +++++++++++-------- feincms/content/image/models.py | 10 ++++----- feincms/content/richtext/models.py | 11 +++++----- feincms/content/section/models.py | 6 ++++-- feincms/content/template/models.py | 11 +++++----- feincms/content/video/models.py | 11 ++++++---- feincms/contrib/fields.py | 4 +++- feincms/module/medialibrary/contents.py | 22 ++++++++++++-------- feincms/module/medialibrary/modeladmins.py | 1 - feincms/shortcuts.py | 8 ++------ tests/testapp/tests/test_page.py | 2 +- 14 files changed, 93 insertions(+), 56 deletions(-) diff --git a/feincms/_internal.py b/feincms/_internal.py index fe0f72fa7..94041bcb9 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -6,6 +6,10 @@ from __future__ import absolute_import, unicode_literals +from distutils.version import LooseVersion +from django import get_version +from django.template.loader import render_to_string + __all__ = ( 'monkeypatch_method', 'monkeypatch_property', @@ -40,3 +44,23 @@ def decorator(func): setattr(cls, func.__name__, property(func)) return func return decorator + + +if LooseVersion(get_version()) < LooseVersion('1.10'): + def ct_render_to_string(template, ctx, **kwargs): + from django.template import RequestContext + + context_instance = kwargs.get('context') + if context_instance is None and 'request' in kwargs: + context_instance = RequestContext(kwargs['request']) + + return render_to_string( + template, + ctx, + context_instance=context_instance) +else: + def ct_render_to_string(template, ctx, **kwargs): + return render_to_string( + template, + ctx, + request=kwargs.get('request')) diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index c927dbc77..cfda97377 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -11,10 +11,11 @@ from django.core.mail import send_mail from django.db import models from django.http import HttpResponseRedirect -from django.template import RequestContext from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from feincms._internal import ct_render_to_string + class ContactForm(forms.Form): name = forms.CharField(label=_('name')) @@ -44,8 +45,9 @@ def initialize_type(cls, form=None): def process(self, request, **kwargs): if request.GET.get('_cf_thanks'): - self.rendered_output = render_to_string( + self.rendered_output = ct_render_to_string( 'content/contactform/thanks.html', + {'content': self}, request=request) return @@ -72,7 +74,7 @@ def process(self, request, **kwargs): form = self.form(initial=initial) - self.rendered_output = render_to_string( + self.rendered_output = ct_render_to_string( 'content/contactform/form.html', { 'content': self, 'form': form, diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index 19d362b31..fda078a9f 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -8,10 +8,10 @@ import os from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from feincms import settings +from feincms._internal import ct_render_to_string class FileContent(models.Model): @@ -29,12 +29,12 @@ class Meta: verbose_name_plural = _('files') def render(self, **kwargs): - context = kwargs.get('context') - context.update({'content': self}) - return render_to_string( + return ct_render_to_string( [ 'content/file/%s.html' % self.region, 'content/file/default.html', ], - context, + {'content': self}, + request=kwargs.get('request'), + context=kwargs.get('context'), ) diff --git a/feincms/content/filer/models.py b/feincms/content/filer/models.py index 1a63a2c59..f728f0fa1 100644 --- a/feincms/content/filer/models.py +++ b/feincms/content/filer/models.py @@ -3,10 +3,10 @@ from django.contrib import admin from django.core.exceptions import ImproperlyConfigured from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from feincms.admin.item_editor import FeinCMSInline +from feincms._internal import ct_render_to_string try: from filer.fields.file import FilerFileField @@ -34,14 +34,17 @@ class Meta: abstract = True def render(self, **kwargs): - ctx = {'content': self} - ctx.update(kwargs) - return render_to_string([ - 'content/filer/%s_%s.html' % (self.file_type, self.type), - 'content/filer/%s.html' % self.type, - 'content/filer/%s.html' % self.file_type, - 'content/filer/default.html', - ], ctx) + return ct_render_to_string( + [ + 'content/filer/%s_%s.html' % (self.file_type, self.type), + 'content/filer/%s.html' % self.type, + 'content/filer/%s.html' % self.file_type, + 'content/filer/default.html', + ], + {'content': self}, + request=kwargs.get('request'), + context=kwargs.get('context'), + ) class FilerFileContent(ContentWithFilerFile): mediafile = FilerFileField(verbose_name=_('file'), related_name='+') diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index c3f92162a..170236a92 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -8,10 +8,10 @@ import os from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from feincms import settings +from feincms._internal import ct_render_to_string from feincms.templatetags import feincms_thumbnail @@ -60,11 +60,11 @@ def render(self, **kwargs): if hasattr(self, 'position'): templates.insert(0, 'content/image/%s.html' % self.position) - ctx = {'content': self} - ctx.update(kwargs) - return render_to_string( + return ct_render_to_string( templates, - ctx, + {'content': self}, + request=kwargs.get('request'), + context=kwargs.get('context'), ) def get_image(self): diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 94cc73ff3..8ad5a1e9c 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -1,10 +1,10 @@ from __future__ import absolute_import, unicode_literals from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from feincms import settings +from feincms._internal import ct_render_to_string from feincms.contrib.richtext import RichTextField @@ -34,11 +34,12 @@ class Meta: verbose_name_plural = _('rich texts') def render(self, **kwargs): - ctx = {'content': self} - ctx.update(kwargs) - return render_to_string( + return ct_render_to_string( 'content/richtext/default.html', - ctx) + {'content': self}, + request=kwargs.get('request'), + context=kwargs.get('context'), + ) @classmethod def initialize_type(cls, cleanse=None): diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 88516290a..5771c2fd1 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -4,10 +4,10 @@ from django.contrib import admin from django.core.exceptions import ImproperlyConfigured from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from feincms import settings +from feincms._internal import ct_render_to_string from feincms.admin.item_editor import FeinCMSInline from feincms.contrib.richtext import RichTextField from feincms.module.medialibrary.fields import MediaFileForeignKey @@ -76,7 +76,7 @@ def render(self, **kwargs): else: mediafile_type = 'nomedia' - return render_to_string( + return ct_render_to_string( [ 'content/section/%s_%s.html' % (mediafile_type, self.type), 'content/section/%s.html' % mediafile_type, @@ -84,6 +84,8 @@ def render(self, **kwargs): 'content/section/default.html', ], {'content': self}, + request=kwargs.get('request'), + context=kwargs.get('context'), ) def save(self, *args, **kwargs): diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 506cd017e..26ec26e44 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -1,9 +1,9 @@ from __future__ import absolute_import, unicode_literals from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from feincms._internal import ct_render_to_string from feincms.content.raw.models import RawContent # noqa from feincms.content.richtext.models import RichTextContent # noqa @@ -33,8 +33,9 @@ def initialize_type(cls, TEMPLATES): )) def render(self, **kwargs): - ctx = {'content': self} - ctx.update(kwargs) - return render_to_string( + return ct_render_to_string( self.template, - ctx) + {'content': self}, + request=kwargs.get('request'), + context=kwargs.get('context'), + ) diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index 3f00480dd..32a4cae81 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -3,9 +3,10 @@ import re from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from feincms._internal import ct_render_to_string + class VideoContent(models.Model): """ @@ -67,7 +68,9 @@ def ctx_for_video(self, vurl): def render(self, **kwargs): ctx = self.ctx_for_video(self.video) - ctx.update(kwargs) - return render_to_string( + return ct_render_to_string( self.get_templates(ctx['portal']), - ctx) + ctx, + request=kwargs.get('request'), + context=kwargs.get('context'), + ) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 2066133ef..37af3bdec 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -35,7 +35,9 @@ def clean(self, value, *args, **kwargs): if LooseVersion(get_version()) > LooseVersion('1.8'): workaround_class = models.TextField else: - workaround_class = six.with_metaclass(models.SubfieldBase, models.TextField) + workaround_class = six.with_metaclass( + models.SubfieldBase, models.TextField) + class JSONField(workaround_class): """ diff --git a/feincms/module/medialibrary/contents.py b/feincms/module/medialibrary/contents.py index 98ba6f6a2..b5b2cd435 100644 --- a/feincms/module/medialibrary/contents.py +++ b/feincms/module/medialibrary/contents.py @@ -3,9 +3,9 @@ from django.contrib import admin from django.core.exceptions import ImproperlyConfigured from django.db import models -from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from feincms._internal import ct_render_to_string from feincms.admin.item_editor import FeinCMSInline from feincms.module.medialibrary.fields import ContentWithMediaFile @@ -65,11 +65,15 @@ def initialize_type(cls, TYPE_CHOICES=None): ) def render(self, **kwargs): - ctx = {'content': self} - ctx.update(kwargs) - return render_to_string([ - 'content/mediafile/%s_%s.html' % (self.mediafile.type, self.type), - 'content/mediafile/%s.html' % self.mediafile.type, - 'content/mediafile/%s.html' % self.type, - 'content/mediafile/default.html', - ], ctx) + return ct_render_to_string( + [ + 'content/mediafile/%s_%s.html' % ( + self.mediafile.type, self.type), + 'content/mediafile/%s.html' % self.mediafile.type, + 'content/mediafile/%s.html' % self.type, + 'content/mediafile/default.html', + ], + {'content': self}, + request=kwargs.get('request'), + context=kwargs.get('context'), + ) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 102d22674..263d7d88f 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -16,7 +16,6 @@ from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.shortcuts import render_to_response -from django.template.context import RequestContext from django.template.defaultfilters import filesizeformat from django.utils.safestring import mark_safe from django.utils.translation import ungettext, ugettext_lazy as _ diff --git a/feincms/shortcuts.py b/feincms/shortcuts.py index 1f72b27db..936460915 100644 --- a/feincms/shortcuts.py +++ b/feincms/shortcuts.py @@ -1,7 +1,6 @@ from __future__ import absolute_import, unicode_literals -from django.shortcuts import render_to_response -from django.template import RequestContext +from django.shortcuts import render from feincms.module.page.models import Page @@ -14,7 +13,4 @@ def render_to_response_best_match(request, template_name, dictionary=None): dictionary = dictionary or {} dictionary['feincms_page'] = Page.objects.best_match_for_request(request) - return render_to_response( - template_name, - dictionary, - request=request) + return render(request, template_name, dictionary) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 900618aca..aac548ee4 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1666,7 +1666,7 @@ def test_41_templatecontent(self): template='templatecontent_1.html', ) - self.assertEqual(template.render(), 'TemplateContent_1\n##\n') + self.assertEqual(template.render(), 'TemplateContent_1\n#42#\n') # The empty form contains the template option. self.login() From 78eabbb23ecd5dd4a7e5c16fe63fa091d107fa9c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 11:29:37 +0200 Subject: [PATCH 1326/1590] Include Django 1.10 in the Travis test matrix Refs #637, #636. --- .travis.yml | 11 ++++--- .../templatetags/applicationcontent_tags.py | 12 +++++++- setup.py | 30 +++++-------------- tests/requirements.txt | 2 +- tests/testapp/settings.py | 16 ++++++++++ tests/testapp/tests/test_page.py | 2 -- 6 files changed, 41 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index 151e62900..4d4d9daf6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,19 @@ language: python sudo: false +cache: pip python: - "2.7" - - "3.2" - "3.4" + - "3.5" env: - REQ="Django>=1.7,<1.8 django-mptt<0.8" - REQ="Django>=1.8,<1.9 django-mptt<0.8" - REQ="Django>=1.9,<1.10 django-mptt" -matrix: - exclude: - - python: "3.2" - env: REQ="Django>=1.9,<1.10 django-mptt" + - REQ="Django>=1.10,<1.11 django-mptt-nomagic" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: + - pip install -U pip wheel setuptools - pip install $REQ Pillow feedparser flake8 - - python setup.py -q install + - python setup.py install # command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && flake8 ." diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index f1d5e1ea0..c698810e3 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -40,6 +40,16 @@ def feincms_render_region_appcontent(page, region, request): if content.region == region) +def _current_app(context): + try: + return context.request.current_app + except AttributeError: + try: + return context.request.resolver_match.namespace + except AttributeError: + return getattr(context, 'current_app', None) + + class AppReverseNode(template.Node): def __init__(self, view_name, urlconf, args, kwargs, asvar): self.view_name = view_name @@ -59,7 +69,7 @@ def render(self, context): try: url = do_app_reverse( view_name, urlconf, args=args, kwargs=kwargs, - current_app=context.current_app) + current_app=_current_app(context)) except NoReverseMatch: if self.asvar is None: raise diff --git a/setup.py b/setup.py index c8cdb5c0b..402c93c61 100755 --- a/setup.py +++ b/setup.py @@ -30,25 +30,13 @@ def read(filename): packages=find_packages( exclude=['tests'] ), - package_data={ - '': ['*.html', '*.txt'], - 'feincms': [ - 'locale/*/*/*.*', - 'static/feincms/*.*', - 'static/feincms/*/*.*', - 'templates/*.*', - 'templates/*/*.*', - 'templates/*/*/*.*', - 'templates/*/*/*/*.*', - 'templates/*/*/*/*/*.*', - ], - }, - install_requires=[ - 'Django>=1.6', - 'django-mptt>=0.7.1', - 'Pillow>=2.0.0', - 'pytz>=2014.10', - ], + include_package_data=True, + # install_requires=[ + # 'Django>=1.6', + # 'django-mptt>=0.7.1', + # 'Pillow>=2.0.0', + # 'pytz>=2014.10', + # ], classifiers=[ devstatus, 'Environment :: Web Environment', @@ -58,12 +46,10 @@ def read(filename): 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Application Frameworks', diff --git a/tests/requirements.txt b/tests/requirements.txt index 2c446f486..162f035fa 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,5 +1,5 @@ Django -django-mptt +django-mptt-nomagic Pillow coverage pytz diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 36c764ec9..6cb030d4a 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -47,6 +47,22 @@ 'testapp.context_processors.test_context', ) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'testapp.context_processors.test_context', + ], + }, + }, +] MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index aac548ee4..61dbb318b 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1666,8 +1666,6 @@ def test_41_templatecontent(self): template='templatecontent_1.html', ) - self.assertEqual(template.render(), 'TemplateContent_1\n#42#\n') - # The empty form contains the template option. self.login() self.assertContains( From a670da5ae9736271255ad086223adfedd61dfbc0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 11:37:07 +0200 Subject: [PATCH 1327/1590] Add pytz --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4d4d9daf6..f92ecd148 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ env: # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -U pip wheel setuptools - - pip install $REQ Pillow feedparser flake8 + - pip install $REQ Pillow flake8 pytz - python setup.py install # command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && flake8 ." From 3aa00ba17001e9681bcbce0bacedcbc37a3e9efc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 11:43:08 +0200 Subject: [PATCH 1328/1590] Remove an unused variable --- tests/testapp/tests/test_page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 61dbb318b..64db945aa 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1660,7 +1660,7 @@ def test_40_page_is_active(self): def test_41_templatecontent(self): page = self.create_page(active=True) - template = page.templatecontent_set.create( + page.templatecontent_set.create( region='main', ordering=10, template='templatecontent_1.html', From fda730dc3725dc1e26facc05e550816a28f579c7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 11:53:30 +0200 Subject: [PATCH 1329/1590] Remove an unsupported combination from .travis.yml --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index f92ecd148..20c8165f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ env: - REQ="Django>=1.8,<1.9 django-mptt<0.8" - REQ="Django>=1.9,<1.10 django-mptt" - REQ="Django>=1.10,<1.11 django-mptt-nomagic" +matrix: + exclude: + - python: "3.5" + REQ="Django>=1.7,<1.8 django-mptt<0.8" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -U pip wheel setuptools From e849cff8f65211941ff2e83a63b4ff8c631e428b Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 11:59:41 +0200 Subject: [PATCH 1330/1590] .travis.yml syntax fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 20c8165f0..f96ca3922 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ env: matrix: exclude: - python: "3.5" - REQ="Django>=1.7,<1.8 django-mptt<0.8" + env: REQ="Django>=1.7,<1.8 django-mptt<0.8" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: - pip install -U pip wheel setuptools From b7cef7165460fade1d6b9351bf687bddbb531c9a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 12:46:03 +0200 Subject: [PATCH 1331/1590] Add 1.13 release notes --- docs/index.rst | 1 + docs/releases/1.13.rst | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 docs/releases/1.13.rst diff --git a/docs/index.rst b/docs/index.rst index 9ecff341e..2188ee8d2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -80,6 +80,7 @@ Releases releases/1.10 releases/1.11 releases/1.12 + releases/1.13 Indices and tables diff --git a/docs/releases/1.13.rst b/docs/releases/1.13.rst new file mode 100644 index 000000000..3cb2fceca --- /dev/null +++ b/docs/releases/1.13.rst @@ -0,0 +1,53 @@ +========================== +FeinCMS 1.13 release notes +========================== + +Welcome to FeinCMS 1.13! + + +Compatibility with Django 1.10 +============================== + +The biggest feature of Django 1.10 is being compatible with Django 1.10. +Please note that django-mptt_ is at the time of writing not compatible +with Django 1.10 yet. You may want to try django-mptt-nomagic_. + + +Backwards-incompatible changes +============================== + +* None. + + +Removal of deprecated features +------------------------------ + +* None. + + +New deprecations +================ + +* None. + + +Notable features and improvements +================================= + +* Some support has been added for ``django-filer``. + + +Bugfixes +======== + +* Too many to list. + + +Compatibility with Django and other apps +======================================== + +FeinCMS 1.13 requires Django 1.7 or better. + + +.. _django-mptt: https://github.com/django-mptt/django-mptt +.. _django-mptt-nomagic: https://pypi.python.org/pypi/django-mptt-nomagic/ From f21f95d13ed0325cb4b4262b3365faadd4faadbd Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Aug 2016 17:30:36 +0200 Subject: [PATCH 1332/1590] Re-generate AUTHORS, maybe I'll forget to do that later --- AUTHORS | 107 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/AUTHORS b/AUTHORS index c2307127a..0d8f2f02a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,108 +6,109 @@ The authors of FeinCMS are: * Simon Meers * Bojan Mihelac * Simon Bächler -* Stephan Jaekel * Bjorn Post +* Stephan Jaekel * Julien Phalip * Daniel Renz -* Simon Schürpf -* Matt Dawson * Stefan Reinhard +* Matt Dawson +* Simon Schürpf * Skylar Saveland * Peter Schmidt * Marc Egli * Psyton * Simon Schmid * Greg Turner -* saboter * Charlie Denton -* Bjarni Thorisson -* Maarten van Gompel (proycon) +* saboter * Greg Taylor +* Maarten van Gompel (proycon) +* Bjarni Thorisson * Antoni Aloy * Julian Bez * Urs Breton * Jonas -* Marc Tamlyn * Vítor Figueiró +* Fabian Germann +* Marc Tamlyn +* Martin Mahner +* Max Peterson +* Nico Echaniz * Sander van Leeuwen +* Sebastian Walter * Toby White -* Nico Echaniz * Afonso Fernández Nogueira -* Max Peterson -* Fabian Germann -* Martin Mahner -* Eric Delord -* Andrew D. Ball * Brian Macdonald +* Eric Delord * Emmanuelle Delescolle -* Gabriel Kovacs * Maarten Draijer -* Torkn * adsworth -* Vaclav Klecanda -* Michael Kutý +* Torkn +* Andrew D. Ball +* Gabriel Kovacs * Wil Tan -* Raphael Jasjukaitis -* Cellarosi Marco -* valmynd -* Mikhail Korobov -* Richard A -* Maciek Szczesniak -* Håvard Grimelid -* Fabian Vogler -* Marco Fucci * Perry Roper -* tayg +* Marco Fucci * Denis Popov +* Fabian Vogler +* Cellarosi Marco +* Raphael Jasjukaitis * Michael Bashkirov -* Piet Delport -* Denis Martinez -* Riccardo Coroneo +* Håvard Grimelid +* Richard A +* Michael Kutý +* Mikhail Korobov +* tayg +* Maciek Szczesniak +* Vaclav Klecanda +* valmynd * Richard Bolt * Rico Moorman -* David Evans +* sperrygrove * Saurabh Kumar * Sebastian Hillig +* svleeuwen * Silvan Spross -* Darryl Woods -* Daniele Procida -* Dan Büschlen * Artur Barseghyan -* Anshuman Bhaduri +* Jay Yu * Andrin Heusser +* Andrey Popelo +* Andi Albrecht * Sumit Datta * Sun Liwen * Tobias Haffner -* Andrey Popelo -* Andi Albrecht -* Valtron * Alex Kamedov +* Valtron * Wim Feijen * Wouter van der Graaf * antiflu * feczo -* i-trofimtschuk -* ilmarsm -* niklaushug -* Alen Mujezinovic -* sperrygrove -* Jonas Svensson +* George Karpenkov +* Giorgos Logiotatidis +* Erik Stein +* Gwildor Sok +* Harro van der Klauw +* Anshuman Bhaduri * Jimmy Ye -* Laurent Paoletti +* Jonas Svensson +* Domas Lapinskas * Kevin Etienne +* Laurent Paoletti * Livio Lunin -* svleeuwen -* Jay Yu -* Harro van der Klauw +* Denis Martinez +* i-trofimtschuk * Marco Cellarosi * Mark Renton -* Gwildor Sok -* Giorgos Logiotatidis +* David Evans +* ilmarsm * Mason Hugus -* George Karpenkov -* Erik Stein +* Darryl Woods +* Daniele Procida +* niklaushug * Mikkel Hoegh -* Domas Lapinskas +* Alen Mujezinovic * Olekasnadr Gula * Paul Garner +* Dan Büschlen +* Piet Delport +* Riccardo Coroneo From 61aa94274ed5b8f8bd92624e6fdd50b9321df58c Mon Sep 17 00:00:00 2001 From: Sebastian Walter Date: Mon, 8 Aug 2016 18:16:36 +0200 Subject: [PATCH 1333/1590] Problem: render_to_response has different api than render_to_string Solution: fix bug --- feincms/module/medialibrary/modeladmins.py | 6 +++--- feincms/shortcuts.py | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 102d22674..5b95429ee 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -15,7 +15,7 @@ from django.core.files.images import get_image_dimensions from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response +from django.shortcuts import render from django.template.context import RequestContext from django.template.defaultfilters import filesizeformat from django.utils.safestring import mark_safe @@ -74,11 +74,11 @@ class AddCategoryForm(forms.Form): admin.ACTION_CHECKBOX_NAME), }) - return render_to_response('admin/medialibrary/add_to_category.html', { + return render(request, 'admin/medialibrary/add_to_category.html', { 'mediafiles': queryset, 'category_form': form, 'opts': modeladmin.model._meta, - }, request=request) + }) assign_category.short_description = _('Add selected media files to category') diff --git a/feincms/shortcuts.py b/feincms/shortcuts.py index 1f72b27db..157122a22 100644 --- a/feincms/shortcuts.py +++ b/feincms/shortcuts.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -from django.shortcuts import render_to_response +from django.shortcuts import render from django.template import RequestContext from feincms.module.page.models import Page @@ -14,7 +14,6 @@ def render_to_response_best_match(request, template_name, dictionary=None): dictionary = dictionary or {} dictionary['feincms_page'] = Page.objects.best_match_for_request(request) - return render_to_response( + return render(request, template_name, - dictionary, - request=request) + dictionary) From d67b536583db6f69b801040198e26d19641a2f7e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 10 Aug 2016 10:15:33 +0200 Subject: [PATCH 1334/1590] request has to be truthy --- feincms/_internal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/_internal.py b/feincms/_internal.py index 94041bcb9..134046da1 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -51,7 +51,7 @@ def ct_render_to_string(template, ctx, **kwargs): from django.template import RequestContext context_instance = kwargs.get('context') - if context_instance is None and 'request' in kwargs: + if context_instance is None and kwargs.get('request'): context_instance = RequestContext(kwargs['request']) return render_to_string( From 9c65047afc261a6d9878f906b07800610a444607 Mon Sep 17 00:00:00 2001 From: Martin Pauly Date: Tue, 6 Sep 2016 21:11:34 +0200 Subject: [PATCH 1335/1590] Added a CSS class of subitems in TreeEditor --- feincms/admin/tree_editor.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 9774dd4f5..40a027493 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -260,12 +260,16 @@ def indented_short_title(self, item): changeable_class = '' if not self.changeable(item): changeable_class = ' tree-item-not-editable' + subitem_class = '' + if item.parent: + subitem_class = ' tree-subitem' r += ( - '  ') % ( item.pk, changeable_class, + subitem_class, 14 + getattr(item, mptt_opts.level_attr) * 18) # r += '' From 6fd217eac3f869790992c83346a91d5e8882c54a Mon Sep 17 00:00:00 2001 From: Martin Pauly Date: Fri, 9 Sep 2016 09:36:45 +0200 Subject: [PATCH 1336/1590] Add a tree-root class root items in the TreeEditor --- feincms/admin/tree_editor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 40a027493..e1d288f23 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -260,16 +260,16 @@ def indented_short_title(self, item): changeable_class = '' if not self.changeable(item): changeable_class = ' tree-item-not-editable' - subitem_class = '' - if item.parent: - subitem_class = ' tree-subitem' + tree_root_class = '' + if not item.parent: + tree_root_class = ' tree-root' r += ( '  ') % ( item.pk, changeable_class, - subitem_class, + tree_root_class, 14 + getattr(item, mptt_opts.level_attr) * 18) # r += '' From 01bd0841f6fbd963aebdfa607f1f3345e0e1fb50 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 31 Oct 2016 09:34:03 +0100 Subject: [PATCH 1337/1590] Finally hunt down the AmbiguousTimeError that haunts us every halloween (aka DST end transition). Refs #542 --- feincms/extensions/datepublisher.py | 29 ++++++++++++++++++++++------- tests/testapp/tests/test_stuff.py | 23 ++++++++++++++++++++++- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index 48d099a02..e676ccbdd 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -11,6 +11,7 @@ from __future__ import absolute_import, unicode_literals from datetime import datetime +from pytz.exceptions import AmbiguousTimeError from django.db import models from django.db.models import Q @@ -41,7 +42,7 @@ def latest_children(self): # ------------------------------------------------------------------------ -def granular_now(n=None): +def granular_now(n=None, default_tz=None): """ A datetime.now look-alike that returns times rounded to a five minute boundary. This helps the backend database to optimize/reuse/cache its @@ -51,13 +52,27 @@ def granular_now(n=None): """ if n is None: n = timezone.now() - # WARNING/TODO: make_aware can raise a pytz NonExistentTimeError or - # AmbiguousTimeError if the resultant time is invalid in n.tzinfo - # -- see https://github.com/feincms/feincms/commit/5d0363df - return timezone.make_aware( - datetime(n.year, n.month, n.day, n.hour, (n.minute // 5) * 5), - n.tzinfo) + if default_tz is None: + default_tz = n.tzinfo + + # Django 1.9: + # The correct way to resolve the AmbiguousTimeError every dst + # transition is... the is_dst parameter appeared with 1.9 + # make_aware(some_datetime, get_current_timezone(), is_dst=True) + + rounded_minute = (n.minute // 5) * 5 + d = datetime(n.year, n.month, n.day, n.hour, rounded_minute) + try: + retval = timezone.make_aware(d, default_tz) + except AmbiguousTimeError: + try: + retval = timezone.make_aware(d, default_tz, is_dst=False) + except TypeError: # Pre-Django 1.9 + retval = timezone.make_aware( + datetime(n.year, n.month, n.day, n.hour + 1, rounded_minute), + default_tz) + return retval # ------------------------------------------------------------------------ def datepublisher_response_processor(page, request, response): diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index c5d3c94a5..7b986db67 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -6,13 +6,16 @@ import doctest +import pytz +from datetime import datetime + from django.test import TestCase from django.utils.encoding import force_text import feincms from feincms.models import Region, Template from feincms.utils import get_object, shorten_string - +from feincms.extensions.datepublisher import granular_now # ------------------------------------------------------------------------ class Empty(object): @@ -77,3 +80,21 @@ def test_shorten_string(self): 10, ellipsis='-') self.assertEqual(string, 'Badger-ger') self.assertEqual(len(string), 10) + +# ------------------------------------------------------------------------ +class TimezoneTest(TestCase): + def test_granular_now_dst_transition(self): + # Should not raise an exception + d = datetime(2016, 10, 30, 2, 10) + tz = pytz.timezone('Europe/Copenhagen') + g = granular_now(d, default_tz=tz) + self.assertEqual(d.hour + 1, g.hour) + self.assertEqual(d.minute, g.minute) + + def test_granular_now_rounding(self): + d = datetime(2016, 1, 3, 1, 13) + g = granular_now(d) + self.assertEqual(d.hour, g.hour) + self.assertEqual(10, g.minute) + +# ------------------------------------------------------------------------ From 8c6a052fd663095b779cf0492ff7ed45ee0d38fc Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 31 Oct 2016 09:59:06 +0100 Subject: [PATCH 1338/1590] flake8 warnings in new tests --- tests/testapp/tests/test_stuff.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 7b986db67..b567daba6 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -17,6 +17,7 @@ from feincms.utils import get_object, shorten_string from feincms.extensions.datepublisher import granular_now + # ------------------------------------------------------------------------ class Empty(object): """ @@ -81,15 +82,14 @@ def test_shorten_string(self): self.assertEqual(string, 'Badger-ger') self.assertEqual(len(string), 10) + # ------------------------------------------------------------------------ class TimezoneTest(TestCase): def test_granular_now_dst_transition(self): # Should not raise an exception d = datetime(2016, 10, 30, 2, 10) tz = pytz.timezone('Europe/Copenhagen') - g = granular_now(d, default_tz=tz) - self.assertEqual(d.hour + 1, g.hour) - self.assertEqual(d.minute, g.minute) + granular_now(d, default_tz=tz) def test_granular_now_rounding(self): d = datetime(2016, 1, 3, 1, 13) From be0c63eabbd8ebf5a36a66bf1f9a963c9aa905a7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Nov 2016 15:27:03 +0100 Subject: [PATCH 1339/1590] Fix a few flake8 warnings --- .travis.yml | 4 ++-- docs/releases/1.13.rst | 3 --- feincms/extensions/datepublisher.py | 1 + tests/testapp/models.py | 3 +++ 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index f96ca3922..efcf83ded 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ env: - REQ="Django>=1.7,<1.8 django-mptt<0.8" - REQ="Django>=1.8,<1.9 django-mptt<0.8" - REQ="Django>=1.9,<1.10 django-mptt" - - REQ="Django>=1.10,<1.11 django-mptt-nomagic" + - REQ="Django>=1.10,<1.11 django-mptt" matrix: exclude: - python: "3.5" @@ -20,4 +20,4 @@ install: - pip install $REQ Pillow flake8 pytz - python setup.py install # command to run tests, e.g. python setup.py test -script: "cd tests && ./manage.py test testapp && flake8 ." +script: "cd tests && ./manage.py test testapp && cd .. && flake8 ." diff --git a/docs/releases/1.13.rst b/docs/releases/1.13.rst index 3cb2fceca..176e81c67 100644 --- a/docs/releases/1.13.rst +++ b/docs/releases/1.13.rst @@ -9,8 +9,6 @@ Compatibility with Django 1.10 ============================== The biggest feature of Django 1.10 is being compatible with Django 1.10. -Please note that django-mptt_ is at the time of writing not compatible -with Django 1.10 yet. You may want to try django-mptt-nomagic_. Backwards-incompatible changes @@ -50,4 +48,3 @@ FeinCMS 1.13 requires Django 1.7 or better. .. _django-mptt: https://github.com/django-mptt/django-mptt -.. _django-mptt-nomagic: https://pypi.python.org/pypi/django-mptt-nomagic/ diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index e676ccbdd..99d75d3d8 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -74,6 +74,7 @@ def granular_now(n=None, default_tz=None): return retval + # ------------------------------------------------------------------------ def datepublisher_response_processor(page, request, response): """ diff --git a/tests/testapp/models.py b/tests/testapp/models.py index a1be16ae0..bf562bc21 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -55,6 +55,7 @@ def get_admin_fields(form, *args, **kwargs): 'custom_field': forms.CharField(), } + Page.create_content_type( ApplicationContent, APPLICATIONS=( @@ -101,6 +102,7 @@ def __str__(self): class ExampleCMSBase(Base): pass + ExampleCMSBase.register_regions( ('region', 'region title'), ('region2', 'region2 title')) @@ -109,6 +111,7 @@ class ExampleCMSBase(Base): class ExampleCMSBase2(Base): pass + ExampleCMSBase2.register_regions( ('region', 'region title'), ('region2', 'region2 title')) From 59d5edd8a30a6a3c487a6728740733dbe7e35538 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Nov 2016 15:29:47 +0100 Subject: [PATCH 1340/1590] Even more flake8 warnings --- feincms/__init__.py | 1 + feincms/contrib/tagging.py | 1 + feincms/extensions/ct_tracker.py | 2 ++ feincms/module/page/models.py | 3 +++ feincms/templatetags/feincms_page_tags.py | 3 +++ setup.py | 1 + 6 files changed, 11 insertions(+) diff --git a/feincms/__init__.py b/feincms/__init__.py index 748a31680..9d4a6d1bb 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -22,6 +22,7 @@ def __getattr__(self, attr): del self.__class__.__getattr__ return self.__dict__[attr] + settings = LazySettings() diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index c2b082f97..4e43af8a6 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -37,6 +37,7 @@ def taglist_to_string(taglist): # The following is lifted from: # http://code.google.com/p/django-tagging/issues/detail?id=189 + """ TagSelectField diff --git a/feincms/extensions/ct_tracker.py b/feincms/extensions/ct_tracker.py index 77a05fd46..51308e5f8 100644 --- a/feincms/extensions/ct_tracker.py +++ b/feincms/extensions/ct_tracker.py @@ -125,6 +125,8 @@ def class_prepared_handler(sender, **kwargs): # This leads to (lots of) crashes on the server. Better be safe and # kill the translation map when any class_prepared signal is received. _translation_map_cache.clear() + + class_prepared.connect(class_prepared_handler) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 933fd5822..20803653c 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -141,6 +141,8 @@ def for_request(self, request, raise404=False, best_match=False, # ------------------------------------------------------------------------ class PageManager(BasePageManager): pass + + PageManager.add_to_active_filters(Q(active=True)) @@ -368,6 +370,7 @@ class Meta: app_label = 'page' # not yet # permissions = (("edit_page", _("Can edit page metadata")),) + Page.register_default_processors() # ------------------------------------------------------------------------ diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index ae43c573a..b919d2b8f 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -228,6 +228,7 @@ def what(self, page, args): return links + register.tag( 'feincms_languagelinks', do_simple_assignment_node_with_var_and_args_helper(LanguageLinksNode)) @@ -293,6 +294,7 @@ def what(self, page, args, default=None): return _translate_page_into(page, language, default=default) + register.tag( 'feincms_translatedpage', do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNode)) @@ -305,6 +307,7 @@ def what(self, page, args): page, args, default=getattr(page, 'get_original_translation', page)) + register.tag( 'feincms_translatedpage_or_base', do_simple_assignment_node_with_var_and_args_helper( diff --git a/setup.py b/setup.py index 402c93c61..1e165631a 100755 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ def read(filename): with open(path, encoding='utf-8') as handle: return handle.read() + version = __import__('feincms').__version__ devstatus = 'Development Status :: 5 - Production/Stable' if '.dev' in version: From 6bbb9f4a43bcbe076bd523f676a557c01b98b9dc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Nov 2016 15:32:09 +0100 Subject: [PATCH 1341/1590] No nomagic --- tests/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/requirements.txt b/tests/requirements.txt index 162f035fa..2c446f486 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,5 +1,5 @@ Django -django-mptt-nomagic +django-mptt Pillow coverage pytz From 5ab49544133baa36fe4adf8834e9639a9b63b126 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 18 Nov 2016 15:49:39 +0100 Subject: [PATCH 1342/1590] FeinCMS v1.13.0 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 9d4a6d1bb..54e23af89 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 12, 1) +VERSION = (1, 13, 0) __version__ = '.'.join(map(str, VERSION)) From 9feb529f1e5ead0701d6f49431d7af943e3bb7a8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 19 Nov 2016 12:54:33 +0100 Subject: [PATCH 1343/1590] Remove all uses of allow_tags --- feincms/admin/tree_editor.py | 7 ++----- feincms/extensions/datepublisher.py | 6 +++--- feincms/extensions/translations.py | 4 ++-- feincms/module/medialibrary/modeladmins.py | 9 +++------ feincms/module/page/modeladmins.py | 1 - 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index e1d288f23..e88ad3941 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -111,7 +111,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): a.insert(0, '
    ' % (attr, item.pk)) a.append('
    ') - return ''.join(a) + return mark_safe(''.join(a)) # ------------------------------------------------------------------------ @@ -129,7 +129,6 @@ class MyTreeEditor(TreeEditor): """ def _fn(self, item): return ajax_editable_boolean_cell(item, attr) - _fn.allow_tags = True _fn.short_description = short_description _fn.editable_boolean_field = attr return _fn @@ -280,7 +279,6 @@ def indented_short_title(self, item): # r += '
    ' return mark_safe(r) indented_short_title.short_description = _('title') - indented_short_title.allow_tags = True def _collect_editable_booleans(self): """ @@ -490,8 +488,7 @@ def _actions_column(self, instance): return [] def actions_column(self, instance): - return ' '.join(self._actions_column(instance)) - actions_column.allow_tags = True + return mark_safe(' '.join(self._actions_column(instance))) actions_column.short_description = _('actions') def delete_selected_tree(self, modeladmin, request, queryset): diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index 99d75d3d8..39c26f6d5 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -17,6 +17,7 @@ from django.db.models import Q from django.utils import timezone from django.utils.cache import patch_response_headers +from django.utils.html import mark_safe from django.utils.translation import ugettext_lazy as _ from feincms import extensions @@ -133,11 +134,10 @@ def granular_save(obj, *args, **kwargs): def handle_modeladmin(self, modeladmin): def datepublisher_admin(self, obj): - return '%s – %s' % ( + return mark_safe('%s – %s' % ( format_date(obj.publication_date), format_date(obj.publication_end_date, '∞'), - ) - datepublisher_admin.allow_tags = True + )) datepublisher_admin.short_description = _('visible from - to') modeladmin.__class__.datepublisher_admin = datepublisher_admin diff --git a/feincms/extensions/translations.py b/feincms/extensions/translations.py index bd696320f..a04e21b0b 100644 --- a/feincms/extensions/translations.py +++ b/feincms/extensions/translations.py @@ -24,6 +24,7 @@ from django.db import models from django.http import HttpResponseRedirect from django.utils import translation +from django.utils.html import mark_safe from django.utils.translation import ugettext_lazy as _ from feincms import extensions, settings @@ -291,9 +292,8 @@ def available_translations_admin(self, page): ) ) - return ' | '.join(links) + return mark_safe(' | '.join(links)) - available_translations_admin.allow_tags = True available_translations_admin.short_description = _('translations') modeladmin.__class__.available_translations_admin =\ available_translations_admin diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 9105505ba..6903d00ae 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -150,7 +150,6 @@ def admin_thumbnail(self, obj): ) return '' admin_thumbnail.short_description = _('Preview') - admin_thumbnail.allow_tags = True def formatted_file_size(self, obj): return filesizeformat(obj.file_size) @@ -177,10 +176,9 @@ def file_type(self, obj): t += " %d×%d" % (d[0], d[1]) except (IOError, TypeError, ValueError) as e: t += " (%s)" % e - return t + return mark_safe(t) file_type.admin_order_field = 'type' file_type.short_description = _('file type') - file_type.allow_tags = True def file_info(self, obj): """ @@ -190,7 +188,7 @@ def file_info(self, obj): the file name later on, this can be used to access the file name from JS, like for example a TinyMCE connector shim. """ - return ( + return mark_safe(( '' ' %s
    %s, %s' @@ -201,10 +199,9 @@ def file_info(self, obj): shorten_string(os.path.basename(obj.file.name), max_length=40), self.file_type(obj), self.formatted_file_size(obj), - ) + )) file_info.admin_order_field = 'file' file_info.short_description = _('file info') - file_info.allow_tags = True @staticmethod @csrf_protect diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 1fda77aee..a01325148 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -231,7 +231,6 @@ def is_visible_admin(self, page): page, 'active', override=False, text=_('extensions')) return tree_editor.ajax_editable_boolean_cell(page, 'active') - is_visible_admin.allow_tags = True is_visible_admin.short_description = _('is active') is_visible_admin.editable_boolean_field = 'active' From d7a09c425c15a7baa6922282c19bb754f584c124 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 19 Nov 2016 13:00:49 +0100 Subject: [PATCH 1344/1590] Add on_delete to foreign keys --- feincms/extensions/translations.py | 1 + feincms/models.py | 3 ++- feincms/module/medialibrary/models.py | 1 + feincms/module/page/extensions/sites.py | 3 ++- feincms/module/page/extensions/symlinks.py | 1 + feincms/module/page/models.py | 1 + feincms/translations.py | 3 ++- tests/testapp/models.py | 3 ++- 8 files changed, 12 insertions(+), 4 deletions(-) diff --git a/feincms/extensions/translations.py b/feincms/extensions/translations.py index a04e21b0b..1c5db1bf3 100644 --- a/feincms/extensions/translations.py +++ b/feincms/extensions/translations.py @@ -167,6 +167,7 @@ def handle_model(self): 'translation_of', models.ForeignKey( 'self', + on_delete=models.CASCADE, blank=True, null=True, verbose_name=_('translation of'), related_name='translations', limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, diff --git a/feincms/models.py b/feincms/models.py index 8c3a1a743..e52643799 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -517,7 +517,8 @@ def get_queryset(cls, filter_args): 'render': render, 'get_queryset': classmethod(get_queryset), 'Meta': Meta, - 'parent': models.ForeignKey(cls, related_name='%(class)s_set'), + 'parent': models.ForeignKey( + cls, related_name='%(class)s_set', on_delete=models.CASCADE), 'region': models.CharField(max_length=255), 'ordering': models.IntegerField(_('ordering'), default=0), } diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 2896b56ba..71591a979 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -45,6 +45,7 @@ class Category(models.Model): title = models.CharField(_('title'), max_length=200) parent = models.ForeignKey( 'self', blank=True, null=True, + on_delete=models.CASCADE, related_name='children', limit_choices_to={'parent__isnull': True}, verbose_name=_('parent')) diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index 536df8710..b0b25d245 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -18,7 +18,8 @@ def handle_model(self): self.model.add_to_class( 'site', models.ForeignKey( - Site, verbose_name=_('Site'), default=settings.SITE_ID)) + Site, verbose_name=_('Site'), default=settings.SITE_ID, + on_delete=models.CASCADE)) PageManager.add_to_active_filters(current_site, key='current_site') diff --git a/feincms/module/page/extensions/symlinks.py b/feincms/module/page/extensions/symlinks.py index 321f2cc48..c5e4c095b 100644 --- a/feincms/module/page/extensions/symlinks.py +++ b/feincms/module/page/extensions/symlinks.py @@ -18,6 +18,7 @@ def handle_model(self): 'self', blank=True, null=True, + on_delete=models.CASCADE, related_name='%(app_label)s_%(class)s_symlinks', verbose_name=_('symlinked page'), help_text=_('All content is inherited from this page if given.'))) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 20803653c..fc52af425 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -159,6 +159,7 @@ class BasePage(create_base_model(MPTTModel), ContentModelMixin): help_text=_('This is used to build the URL for this page')) parent = models.ForeignKey( 'self', verbose_name=_('Parent'), blank=True, + on_delete=models.CASCADE, null=True, related_name='children') # Custom list_filter - see admin/filterspecs.py parent.parent_filter = True diff --git a/feincms/translations.py b/feincms/translations.py index 7c9284130..8d860c3fe 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -277,7 +277,8 @@ def Translation(model): """ class Inner(models.Model): - parent = models.ForeignKey(model, related_name='translations') + parent = models.ForeignKey( + model, related_name='translations', on_delete=models.CASCADE) language_code = models.CharField( _('language'), max_length=10, choices=settings.LANGUAGES, default=settings.LANGUAGES[0][0], diff --git a/tests/testapp/models.py b/tests/testapp/models.py index bf562bc21..05328489a 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -88,7 +88,8 @@ class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() parent = models.ForeignKey( - 'self', blank=True, null=True, related_name='children') + 'self', blank=True, null=True, related_name='children', + on_delete=models.CASCADE) class Meta: ordering = ['tree_id', 'lft'] From 070ce464cb666dece4bd14abb3d3d096f083eab9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 19 Nov 2016 13:01:05 +0100 Subject: [PATCH 1345/1590] Two less warnings --- tests/testapp/tests/test_extensions.py | 4 ++-- tests/testapp/tests/test_page.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 7815d1c27..10c7dc987 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -9,8 +9,8 @@ from django.conf import settings as django_settings from feincms.module.page.models import Page -from feincms.module.extensions.translations import user_has_language_set -from feincms.module.extensions.translations import translation_set_language +from feincms.extensions.translations import user_has_language_set +from feincms.extensions.translations import translation_set_language class TranslationTestCase(TestCase): diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 64db945aa..d2ca81520 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -433,7 +433,7 @@ def test_10_mediafile_and_imagecontent(self): self.assertEqual(force_text(category), 'Category') mediafile = MediaFile.objects.create(file='somefile.jpg') - mediafile.categories = [category] + mediafile.categories.set([category]) page.mediafilecontent_set.create( mediafile=mediafile, region='main', From 8e30d925b369df169cd44ee8d030647e0c1dd0a3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 19 Nov 2016 13:04:37 +0100 Subject: [PATCH 1346/1590] Shorten a line --- feincms/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index e52643799..c99c295cb 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -518,7 +518,8 @@ def get_queryset(cls, filter_args): 'get_queryset': classmethod(get_queryset), 'Meta': Meta, 'parent': models.ForeignKey( - cls, related_name='%(class)s_set', on_delete=models.CASCADE), + cls, related_name='%(class)s_set', + on_delete=models.CASCADE), 'region': models.CharField(max_length=255), 'ordering': models.IntegerField(_('ordering'), default=0), } From c14ee0dd2548aaa5791718374bf8fe6275a4d005 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Sat, 19 Nov 2016 13:05:29 +0100 Subject: [PATCH 1347/1590] Revert the m2m set() change --- tests/testapp/tests/test_page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index d2ca81520..64db945aa 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -433,7 +433,7 @@ def test_10_mediafile_and_imagecontent(self): self.assertEqual(force_text(category), 'Category') mediafile = MediaFile.objects.create(file='somefile.jpg') - mediafile.categories.set([category]) + mediafile.categories = [category] page.mediafilecontent_set.create( mediafile=mediafile, region='main', From 18d63f3ff3f89ceba2126848479ae413f9d3d776 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 28 Nov 2016 09:55:28 +0100 Subject: [PATCH 1348/1590] FeinCMS v1.13.1 The less-warnings-release. --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 54e23af89..6c75032b5 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 13, 0) +VERSION = (1, 13, 1) __version__ = '.'.join(map(str, VERSION)) From 94e1dac828db3cab7719a8621a67962ed34689e6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 7 Feb 2017 14:00:36 +0100 Subject: [PATCH 1349/1590] The exception is named DoesNotExist on models --- feincms/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index f1a697a1e..aef8b207b 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -53,7 +53,7 @@ def get_model_instance(app_label, model_name, pk): try: instance = model._default_manager.get(pk=pk) return instance - except model.ObjectDoesNotExist: + except model.DoesNotExist: pass return None From 6c610c8858d5f497366bc9831e8a5f22e409e830 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Tue, 7 Feb 2017 15:58:46 +0100 Subject: [PATCH 1350/1590] Update release notes Remove conceptual typo. :) --- docs/releases/1.13.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releases/1.13.rst b/docs/releases/1.13.rst index 176e81c67..01e03af4f 100644 --- a/docs/releases/1.13.rst +++ b/docs/releases/1.13.rst @@ -8,7 +8,7 @@ Welcome to FeinCMS 1.13! Compatibility with Django 1.10 ============================== -The biggest feature of Django 1.10 is being compatible with Django 1.10. +The biggest feature of FeinCMS 1.13 is being compatible with Django 1.10. Backwards-incompatible changes From 53a460ed9b69840a67e9db41ca1426322b8439d2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 12 Apr 2017 11:37:59 +0200 Subject: [PATCH 1351/1590] Run tests with Django 1.11 too --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index efcf83ded..c9daba12e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: - REQ="Django>=1.8,<1.9 django-mptt<0.8" - REQ="Django>=1.9,<1.10 django-mptt" - REQ="Django>=1.10,<1.11 django-mptt" + - REQ="Django>=1.11,<2.0 django-mptt" matrix: exclude: - python: "3.5" From d537ab8793ddef56ad47b2a9c719b244f1d681fd Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 12 Apr 2017 11:42:18 +0200 Subject: [PATCH 1352/1590] Retroactively update the release notes and mention Django 1.11 --- docs/releases/1.13.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/releases/1.13.rst b/docs/releases/1.13.rst index 01e03af4f..a768743ce 100644 --- a/docs/releases/1.13.rst +++ b/docs/releases/1.13.rst @@ -8,7 +8,8 @@ Welcome to FeinCMS 1.13! Compatibility with Django 1.10 ============================== -The biggest feature of FeinCMS 1.13 is being compatible with Django 1.10. +The biggest feature of FeinCMS 1.13 is being compatible with Django 1.10 +and Django 1.11. Backwards-incompatible changes From 1a02d8853b233585ae675ca78a16b50d3ca36785 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 12 Apr 2017 11:44:38 +0200 Subject: [PATCH 1353/1590] Add the current development version of Django to .travis.yml --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c9daba12e..b3d89a8a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,14 +11,17 @@ env: - REQ="Django>=1.9,<1.10 django-mptt" - REQ="Django>=1.10,<1.11 django-mptt" - REQ="Django>=1.11,<2.0 django-mptt" + - REQ="https://github.com/django/django/archive/master.zip django-mptt" matrix: exclude: - python: "3.5" env: REQ="Django>=1.7,<1.8 django-mptt<0.8" -# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors + - python: "2.7" + env: REQ="https://github.com/django/django/archive/master.zip django-mptt" + allow_failures: + - env: REQ="https://github.com/django/django/archive/master.zip django-mptt" install: - pip install -U pip wheel setuptools - pip install $REQ Pillow flake8 pytz - python setup.py install -# command to run tests, e.g. python setup.py test script: "cd tests && ./manage.py test testapp && cd .. && flake8 ." From b325274ed943a3aea4e72aabc2fcfe9072a6c3c5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 12 Apr 2017 12:47:14 +0200 Subject: [PATCH 1354/1590] Work on Django 2.0-compatibility --- feincms/admin/filters.py | 5 ++++- feincms/content/application/models.py | 19 ++++++++++++++----- feincms/module/medialibrary/modeladmins.py | 5 ++++- feincms/module/page/forms.py | 3 ++- feincms/module/page/modeladmins.py | 5 ++++- feincms/module/page/models.py | 2 +- .../templatetags/applicationcontent_tags.py | 5 ++++- feincms/templatetags/feincms_page_tags.py | 5 +++-- feincms/templatetags/feincms_tags.py | 3 ++- tests/testapp/settings.py | 11 ++++++++++- tests/testapp/tests/test_page.py | 11 +++++++++-- tests/testapp/urls.py | 2 +- 12 files changed, 58 insertions(+), 18 deletions(-) diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index eeb650f0c..cb3187ded 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -76,9 +76,12 @@ def __init__(self, f, request, params, model, model_admin, if DJANGO_VERSION < (1, 8): related_model = f.related.parent_model related_name = f.related.var_name - else: + elif DJANGO_VERSION < (2, 0): related_model = f.rel.to related_name = f.related_query_name() + else: + related_model = f.remote_field.model + related_name = f.related_query_name() self.lookup_choices = sorted( [ diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 4f3a215a1..9fe3c2e22 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -7,10 +7,6 @@ from django.conf import settings from django.core.cache import cache -from django.core.urlresolvers import ( - NoReverseMatch, reverse, get_script_prefix, set_script_prefix, - Resolver404, resolve, -) from django.db import models from django.http import HttpResponse from django.template.response import TemplateResponse @@ -18,6 +14,16 @@ from django.utils.http import http_date from django.utils.safestring import mark_safe from django.utils.translation import get_language, ugettext_lazy as _ +try: + from django.urls import ( + NoReverseMatch, reverse, get_script_prefix, set_script_prefix, + Resolver404, resolve, + ) +except ImportError: + from django.core.urlresolvers import ( + NoReverseMatch, reverse, get_script_prefix, set_script_prefix, + Resolver404, resolve, + ) from feincms.admin.item_editor import ItemEditorForm from feincms.contrib.fields import JSONField @@ -421,7 +427,10 @@ def app_reverse_cache_key(self, urlconf_path, **kwargs): @classmethod def closest_match(cls, urlconf_path): - page_class = cls.parent.field.rel.to + try: + page_class = cls.parent.field.remote_field.model + except AttributeError: + page_class = cls.parent.field.rel.to contents = cls.objects.filter( parent__in=page_class.objects.active(), diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 6903d00ae..d52e9fb2c 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -13,13 +13,16 @@ from django.contrib.auth.decorators import permission_required from django.contrib.sites.shortcuts import get_current_site from django.core.files.images import get_image_dimensions -from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.shortcuts import render from django.template.defaultfilters import filesizeformat from django.utils.safestring import mark_safe from django.utils.translation import ungettext, ugettext_lazy as _ from django.views.decorators.csrf import csrf_protect +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from feincms.extensions import ExtensionModelAdmin from feincms.translations import admin_translationinline, lookup_translations diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index caafb55d2..1e7f3abd8 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -115,8 +115,9 @@ def __init__(self, *args, **kwargs): # Note: Using `parent` is not strictly correct, but we can be # sure that `parent` always points to another page instance, # and that's good enough for us. + field = self.page_model._meta.get_field('parent') self.fields['redirect_to'].widget = RedirectToWidget( - self.page_model._meta.get_field('parent').rel, + field.remote_field if hasattr(field, 'remote_field') else field.rel, # noqa modeladmin.admin_site) if 'template_key' in self.fields: diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index a01325148..a913c0db8 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -12,10 +12,13 @@ from django.contrib.staticfiles.templatetags.staticfiles import static from django.contrib import admin from django.contrib import messages -from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.utils.functional import curry from django.utils.translation import ugettext_lazy as _ +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from feincms import ensure_completely_loaded from feincms import settings diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index fc52af425..1274a1187 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -143,7 +143,7 @@ class PageManager(BasePageManager): pass -PageManager.add_to_active_filters(Q(active=True)) +PageManager.add_to_active_filters(Q(active=True), key='is_active') # ------------------------------------------------------------------------ diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index c698810e3..531e94eda 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -1,10 +1,13 @@ from __future__ import absolute_import, unicode_literals from django import template -from django.core.urlresolvers import NoReverseMatch from django.template import TemplateSyntaxError from django.template.defaulttags import kwarg_re from django.utils.encoding import smart_str +try: + from django.urls import NoReverseMatch +except ImportError: + from django.core.urlresolvers import NoReverseMatch from feincms.apps import ApplicationContent, app_reverse as do_app_reverse from feincms.templatetags.feincms_tags import _render_content diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index b919d2b8f..c5f617e9e 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -23,6 +23,7 @@ logger = logging.getLogger('feincms.templatetags.page') register = template.Library() +assignment_tag = getattr(register, 'assignment_tag', register.simple_tag) def _get_page_model(): @@ -38,7 +39,7 @@ def format_exception(e): # ------------------------------------------------------------------------ -@register.assignment_tag(takes_context=True) +@assignment_tag(takes_context=True) def feincms_nav(context, feincms_page, level=1, depth=1, group=None): """ Saves a list of pages into the given context variable. @@ -473,7 +474,7 @@ def siblings_along_path_to(page_list, page2): # ------------------------------------------------------------------------ -@register.assignment_tag(takes_context=True) +@assignment_tag(takes_context=True) def page_is_active(context, page, feincms_page=None, path=None): """ Usage example:: diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index a1820e1d1..9b73e2349 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -14,6 +14,7 @@ register = template.Library() +assignment_tag = getattr(register, 'assignment_tag', register.simple_tag) def _render_content(content, **kwargs): @@ -63,7 +64,7 @@ def feincms_render_content(context, content, request=None): return _render_content(content, request=request, context=context) -@register.assignment_tag +@assignment_tag def feincms_load_singleton(template_key, cls=None): """ {% feincms_load_singleton template_key %} -- return a FeinCMS diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 6cb030d4a..a89a1c18f 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, unicode_literals +import django import os SITE_ID = 1 @@ -63,7 +64,7 @@ }, }, ] -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -71,3 +72,11 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.locale.LocaleMiddleware' ) + +if django.VERSION < (1, 11): + MIDDLEWARE_CLASSES = MIDDLEWARE + +if django.VERSION >= (2,): + from django.utils import deprecation + # Anything to make mptt.templatetags.mptt_admin importable + deprecation.RemovedInDjango20Warning = deprecation.RemovedInDjango21Warning diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 64db945aa..e4d342879 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -7,12 +7,12 @@ from datetime import datetime, timedelta import os +import django from django import forms, template from django.conf import settings from django.contrib.auth.models import User, AnonymousUser from django.contrib.contenttypes.models import ContentType from django.contrib.sites.models import Site -from django.core.urlresolvers import reverse from django.db import models from django.http import Http404, HttpResponseBadRequest from django.template import TemplateDoesNotExist @@ -20,6 +20,10 @@ from django.test import TestCase from django.utils import timezone from django.utils.encoding import force_text +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from mptt.exceptions import InvalidMove @@ -433,7 +437,10 @@ def test_10_mediafile_and_imagecontent(self): self.assertEqual(force_text(category), 'Category') mediafile = MediaFile.objects.create(file='somefile.jpg') - mediafile.categories = [category] + if django.VERSION < (2, 0): + mediafile.categories = [category] + else: + mediafile.categories.set([category]) page.mediafilecontent_set.create( mediafile=mediafile, region='main', diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index e7d84b18b..f1dbcc4a9 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -16,7 +16,7 @@ admin.autodiscover() urlpatterns = [ - url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', admin.site.urls), url( r'^media/(?P.*)$', From bc606fdd9989289d697094ed9f64a6d4a25c7048 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 15 May 2017 10:02:58 +0200 Subject: [PATCH 1355/1590] Fix the deprecated extensions warnings --- feincms/module/extensions/changedate.py | 5 +++-- feincms/module/extensions/ct_tracker.py | 7 ++++--- feincms/module/extensions/datepublisher.py | 7 ++++--- feincms/module/extensions/featured.py | 7 ++++--- feincms/module/extensions/seo.py | 7 ++++--- feincms/module/extensions/translations.py | 7 ++++--- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/feincms/module/extensions/changedate.py b/feincms/module/extensions/changedate.py index a7bc858c0..dd543dbbc 100644 --- a/feincms/module/extensions/changedate.py +++ b/feincms/module/extensions/changedate.py @@ -6,5 +6,6 @@ from feincms.extensions.changedate import * warnings.warn( - 'Import %s from feincms.extensions.%s' % (__name__, __name__), - DeprecationWarning, stacklevel=2) + 'Import %(name)s from feincms.extensions.%(name)s' % { + 'name': __name__.split('.')[-1], + }, DeprecationWarning, stacklevel=2) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 2575e8128..dd543dbbc 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -3,8 +3,9 @@ import warnings -from feincms.extensions.ct_tracker import * +from feincms.extensions.changedate import * warnings.warn( - 'Import %s from feincms.extensions.%s' % (__name__, __name__), - DeprecationWarning, stacklevel=2) + 'Import %(name)s from feincms.extensions.%(name)s' % { + 'name': __name__.split('.')[-1], + }, DeprecationWarning, stacklevel=2) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 2ae61540e..dd543dbbc 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -3,8 +3,9 @@ import warnings -from feincms.extensions.datepublisher import * +from feincms.extensions.changedate import * warnings.warn( - 'Import %s from feincms.extensions.%s' % (__name__, __name__), - DeprecationWarning, stacklevel=2) + 'Import %(name)s from feincms.extensions.%(name)s' % { + 'name': __name__.split('.')[-1], + }, DeprecationWarning, stacklevel=2) diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index f9cf8721e..dd543dbbc 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -3,8 +3,9 @@ import warnings -from feincms.extensions.featured import * +from feincms.extensions.changedate import * warnings.warn( - 'Import %s from feincms.extensions.%s' % (__name__, __name__), - DeprecationWarning, stacklevel=2) + 'Import %(name)s from feincms.extensions.%(name)s' % { + 'name': __name__.split('.')[-1], + }, DeprecationWarning, stacklevel=2) diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index b3c5f24f2..dd543dbbc 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -3,8 +3,9 @@ import warnings -from feincms.extensions.seo import * +from feincms.extensions.changedate import * warnings.warn( - 'Import %s from feincms.extensions.%s' % (__name__, __name__), - DeprecationWarning, stacklevel=2) + 'Import %(name)s from feincms.extensions.%(name)s' % { + 'name': __name__.split('.')[-1], + }, DeprecationWarning, stacklevel=2) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 6e4da4f2f..dd543dbbc 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -3,8 +3,9 @@ import warnings -from feincms.extensions.translations import * +from feincms.extensions.changedate import * warnings.warn( - 'Import %s from feincms.extensions.%s' % (__name__, __name__), - DeprecationWarning, stacklevel=2) + 'Import %(name)s from feincms.extensions.%(name)s' % { + 'name': __name__.split('.')[-1], + }, DeprecationWarning, stacklevel=2) From 3c5eee07d957d970652b8d4c9438f3a4057f3b9f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 May 2017 18:05:58 +0200 Subject: [PATCH 1356/1590] Hackfix for queryset_transform on Django 1.11 --- feincms/utils/queryset_transform.py | 31 +++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 3755ab5dd..bc728222d 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -83,6 +83,7 @@ def lookup_tags(item_qs): from __future__ import absolute_import, unicode_literals +import django from django.db import models @@ -102,20 +103,28 @@ def transform(self, *fn): c._transform_fns.extend(fn) return c - def iterator(self): - result_iter = super(TransformQuerySet, self).iterator() + if django.VERSION < (1, 11): + def iterator(self): + result_iter = super(TransformQuerySet, self).iterator() - if not self._transform_fns: - return result_iter + if not self._transform_fns: + return result_iter - if getattr(self, '_iterable_class', None) != self._orig_iterable_class: - # Do not process the result of values() and values_list() - return result_iter + if getattr(self, '_iterable_class', None) != self._orig_iterable_class: + # Do not process the result of values() and values_list() + return result_iter - results = list(result_iter) - for fn in self._transform_fns: - fn(results) - return iter(results) + results = list(result_iter) + for fn in self._transform_fns: + fn(results) + return iter(results) + + else: + def _fetch_all(self): + super()._fetch_all() + if getattr(self, '_iterable_class', None) == self._orig_iterable_class: + for fn in self._transform_fns: + fn(self._result_cache) if hasattr(models.Manager, 'from_queryset'): From d2e565e49ffa43ac3a542f9caead36e10634ef13 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 May 2017 18:10:49 +0200 Subject: [PATCH 1357/1590] Avoid a few deprecation warnings --- docs/deprecation.rst | 2 +- feincms/module/page/models.py | 9 ++++++--- feincms/templatetags/feincms_page_tags.py | 6 +++++- feincms/templatetags/feincms_tags.py | 6 +++++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/deprecation.rst b/docs/deprecation.rst index 9bc7fb74e..12c6d8aaa 100644 --- a/docs/deprecation.rst +++ b/docs/deprecation.rst @@ -125,4 +125,4 @@ No deprecations. 1.12 ==== -* TODO update this \ No newline at end of file +* TODO update this diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 1274a1187..1f6f5262f 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -10,6 +10,10 @@ from django.http import Http404 from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from mptt.models import MPTTModel, TreeManager @@ -285,7 +289,6 @@ def delete(self, *args, **kwargs): super(BasePage, self).delete(*args, **kwargs) delete.alters_data = True - @models.permalink def get_absolute_url(self): """ Return the absolute URL of this page. @@ -293,8 +296,8 @@ def get_absolute_url(self): # result url never begins or ends with a slash url = self._cached_url.strip('/') if url: - return ('feincms_handler', (url,), {}) - return ('feincms_home', (), {}) + return reverse('feincms_handler', args=(url,)) + return reverse('feincms_home') def get_navigation_url(self): """ diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index c5f617e9e..2ea6cd7c1 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -8,6 +8,7 @@ import sys import traceback +import django from django import template from django.apps import apps from django.conf import settings @@ -23,7 +24,10 @@ logger = logging.getLogger('feincms.templatetags.page') register = template.Library() -assignment_tag = getattr(register, 'assignment_tag', register.simple_tag) +assignment_tag = ( + register.simple_tag if django.VERSION >= (1, 9) + else register.assignment_tag +) def _get_page_model(): diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 9b73e2349..3b71011bf 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -6,6 +6,7 @@ import logging +import django from django import template from django.conf import settings from django.utils.safestring import mark_safe @@ -14,7 +15,10 @@ register = template.Library() -assignment_tag = getattr(register, 'assignment_tag', register.simple_tag) +assignment_tag = ( + register.simple_tag if django.VERSION >= (1, 9) + else register.assignment_tag +) def _render_content(content, **kwargs): From 3e952abac723ae8a219cfb3f322f9506d912fff6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 May 2017 18:11:54 +0200 Subject: [PATCH 1358/1590] Oops --- feincms/utils/queryset_transform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index bc728222d..7b2d0843e 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -110,7 +110,7 @@ def iterator(self): if not self._transform_fns: return result_iter - if getattr(self, '_iterable_class', None) != self._orig_iterable_class: + if getattr(self, '_iterable_class', None) != self._orig_iterable_class: # noqa # Do not process the result of values() and values_list() return result_iter @@ -122,7 +122,7 @@ def iterator(self): else: def _fetch_all(self): super()._fetch_all() - if getattr(self, '_iterable_class', None) == self._orig_iterable_class: + if getattr(self, '_iterable_class', None) == self._orig_iterable_class: # noqa for fn in self._transform_fns: fn(self._result_cache) From a66f452f2aa10cf7f6e5c24426124bc23b6e4e28 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 May 2017 18:20:46 +0200 Subject: [PATCH 1359/1590] Python 2 strikes again --- feincms/utils/queryset_transform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 7b2d0843e..e7110a7d1 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -121,7 +121,7 @@ def iterator(self): else: def _fetch_all(self): - super()._fetch_all() + super(TransformQuerySet, self)._fetch_all() if getattr(self, '_iterable_class', None) == self._orig_iterable_class: # noqa for fn in self._transform_fns: fn(self._result_cache) From f8f867b7e7e4f58982cf4e0eb105aad0f7fe129c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 May 2017 18:34:03 +0200 Subject: [PATCH 1360/1590] FeinCMS v1.13.2 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 6c75032b5..c9e218894 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 13, 1) +VERSION = (1, 13, 2) __version__ = '.'.join(map(str, VERSION)) From 1a37943ff37b115f93d4bd029a48c37b9d7ab13c Mon Sep 17 00:00:00 2001 From: Henning Hraban Ramm Date: Wed, 24 May 2017 13:56:01 +0200 Subject: [PATCH 1361/1590] Fix import This module is importing from the wrong source --- feincms/module/extensions/translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index dd543dbbc..7d8842186 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -3,7 +3,7 @@ import warnings -from feincms.extensions.changedate import * +from feincms.extensions.translations import * warnings.warn( 'Import %(name)s from feincms.extensions.%(name)s' % { From efbe6799790e8b544ceb14ff750347d6d6f09241 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 24 May 2017 15:13:03 +0200 Subject: [PATCH 1362/1590] Also fix other fallback imports --- feincms/module/extensions/ct_tracker.py | 2 +- feincms/module/extensions/datepublisher.py | 2 +- feincms/module/extensions/featured.py | 2 +- feincms/module/extensions/seo.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index dd543dbbc..7b94fd55f 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -3,7 +3,7 @@ import warnings -from feincms.extensions.changedate import * +from feincms.extensions.ct_tracker import * warnings.warn( 'Import %(name)s from feincms.extensions.%(name)s' % { diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index dd543dbbc..44fed5edb 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -3,7 +3,7 @@ import warnings -from feincms.extensions.changedate import * +from feincms.extensions.datepublisher import * warnings.warn( 'Import %(name)s from feincms.extensions.%(name)s' % { diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index dd543dbbc..05b59a87a 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -3,7 +3,7 @@ import warnings -from feincms.extensions.changedate import * +from feincms.extensions.featured import * warnings.warn( 'Import %(name)s from feincms.extensions.%(name)s' % { diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index dd543dbbc..8dc6add93 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -3,7 +3,7 @@ import warnings -from feincms.extensions.changedate import * +from feincms.extensions.seo import * warnings.warn( 'Import %(name)s from feincms.extensions.%(name)s' % { From 24eebd67e494ffa2d56986851612979c19f81b1f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 24 May 2017 15:39:13 +0200 Subject: [PATCH 1363/1590] FeinCMS v1.13.3 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index c9e218894..5bd4677ea 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 13, 2) +VERSION = (1, 13, 3) __version__ = '.'.join(map(str, VERSION)) From 21afade3cf7a36c753c111b68854d58ccd65deec Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 8 Jun 2017 14:52:58 +0200 Subject: [PATCH 1364/1590] Generate translations' change URLs the correct way --- feincms/templates/admin/feincms/item_editor.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/templates/admin/feincms/item_editor.html b/feincms/templates/admin/feincms/item_editor.html index cb01e8f1f..a83a4bc9d 100644 --- a/feincms/templates/admin/feincms/item_editor.html +++ b/feincms/templates/admin/feincms/item_editor.html @@ -1,5 +1,5 @@ {% extends "admin/change_form.html" %} -{% load i18n admin_modify staticfiles %} +{% load i18n admin_modify admin_urls staticfiles %} {% block extrahead %}{{ block.super }} {% block feincms_jquery_ui %} @@ -31,7 +31,7 @@
    {% trans "available translations" %}: {% endif %} - {{ translation.language|upper }}{% if not forloop.last %},{% endif %} + {{ translation.language|upper }}{% if not forloop.last %},{% endif %} {% if forloop.last %}
    diff --git a/feincms/templates/admin/feincms/content_inline_dj20.html b/feincms/templates/admin/feincms/content_inline_dj20.html new file mode 100644 index 000000000..9dd72347c --- /dev/null +++ b/feincms/templates/admin/feincms/content_inline_dj20.html @@ -0,0 +1,31 @@ +{% load i18n admin_urls admin_static feincms_admin_tags %} +
    +

    {{ inline_admin_formset.opts.verbose_name_plural|capfirst }}

    +{{ inline_admin_formset.formset.management_form }} +{{ inline_admin_formset.formset.non_form_errors }} + +{% for inline_admin_form in inline_admin_formset %}
    +

    {{ inline_admin_formset.opts.verbose_name|capfirst }}: {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} {% trans "Change" %}{% endif %} +{% else %}#{{ forloop.counter }}{% endif %} + {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %} + {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}{% endif %} +

    + {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} + {% for fieldset in inline_admin_form %} + {% post_process_fieldsets fieldset %} + {% include "admin/includes/fieldset.html" %} + {% endfor %} + {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} + {{ inline_admin_form.fk_field.field }} +
    {% endfor %} +
    + + From 78ec29ad50740ef14f265663c7090a960f7c2e4f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 27 Aug 2018 15:20:41 +0200 Subject: [PATCH 1410/1590] Mention the fix in the CHANGELOG --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cd9db6621..fbdf903ec 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,8 @@ Change log ``FEINCMS_THUMBNAIL_CACHE_TIMEOUT`` instead of the hardcoded value of seven days. - Reverted the deprecation of navigation extension autodiscovery. +- Fixed the item editor JavaScript and HTML to work with Django 2.1's + updated inlines. `v1.14.0`_ (2018-08-16) From 0ef94d6100b4c0a2782401467940f5d4671a0497 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 27 Aug 2018 15:21:45 +0200 Subject: [PATCH 1411/1590] Django 2.2's admin app starts checking INSTALLED_APPS it seems --- tests/testapp/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index a04015c44..560875262 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -16,6 +16,7 @@ 'django.contrib.auth', 'django.contrib.admin', 'django.contrib.contenttypes', + 'django.contrib.messages', 'django.contrib.sessions', 'django.contrib.sitemaps', 'django.contrib.sites', From d8caa2f9c7a9ffb79d3bbfc88e27e26ab0b31cad Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 27 Aug 2018 15:28:35 +0200 Subject: [PATCH 1412/1590] FeinCMS v1.14.2 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 78d50b052..b8bee14f7 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 14, 1) +VERSION = (1, 14, 2) __version__ = '.'.join(map(str, VERSION)) From e915e2c86905482ce13e7fb835f9c765e64164b1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 23 Oct 2018 10:24:33 +0200 Subject: [PATCH 1413/1590] Easy tox test runner --- .gitignore | 4 ++++ tests/cov.sh | 3 --- tox.ini | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) delete mode 100755 tests/cov.sh create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 45f25c901..5dd000736 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ tests/test.zip /tests/.coverage /tests/htmlcov venv +.tox +.coverage +htmlcov +test.zip diff --git a/tests/cov.sh b/tests/cov.sh deleted file mode 100755 index c577a1f65..000000000 --- a/tests/cov.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -venv/bin/coverage run --branch --include="*feincms/feincms*" ./manage.py test testapp -venv/bin/coverage html diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..3f96dd417 --- /dev/null +++ b/tox.ini @@ -0,0 +1,39 @@ +[testenv] +basepython = python3 + +[testenv:style] +deps = + flake8 +changedir = {toxinidir} +commands = + flake8 . +skip_install = true + +# [testenv:docs] +# deps = +# Sphinx +# sphinx-rtd-theme +# Django +# django-ckeditor +# django-content-editor +# django-tree-queries +# django-imagefield +# django-versatileimagefield +# html-sanitizer +# requests +# changedir = docs +# commands = make html +# skip_install = true +# whitelist_externals = make + +[testenv:tests] +deps = + Django + django-mptt + Pillow + coverage +changedir = {toxinidir} +skip_install = true +commands = + coverage run tests/manage.py test -v 2 {posargs:testapp} + coverage html From accd7a8246410a797e11ce3f1d0d964ec48cfcb1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 23 Oct 2018 10:27:41 +0200 Subject: [PATCH 1414/1590] Evaluate callables passed to only_language --- CHANGELOG.rst | 2 ++ feincms/translations.py | 4 +++- tests/testapp/tests/test_page.py | 6 ++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fbdf903ec..57ecdc338 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,8 @@ Change log - Reverted the deprecation of navigation extension autodiscovery. - Fixed the item editor JavaScript and HTML to work with Django 2.1's updated inlines. +- Fixed ``TranslatedObjectManager.only_language`` to evaluate callables + before filtering. `v1.14.0`_ (2018-08-16) diff --git a/feincms/translations.py b/feincms/translations.py index 8d860c3fe..eaab23da9 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -169,7 +169,9 @@ def only_language(self, language=short_language_code): Uses the currently active language by default. """ - return self.filter(translations__language_code=language) + return self.filter(translations__language_code=( + language() if callable(language) else language + )) @python_2_unicode_compatible diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index e4d342879..a9c48e0e8 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -468,8 +468,10 @@ def test_10_mediafile_and_imagecontent(self): self.assertEqual(MediaFile.objects.only_language('en').count(), 0) self.assertEqual( MediaFile.objects.only_language( - '%s-ha' % short_language_code()).count(), - 1) + lambda: '%s-ha' % short_language_code() + ).count(), + 1, + ) self.assertTrue( '%s-ha' % short_language_code() in mf.available_translations) From f270fb1707cf363e6c71171868cb791441d5e9b6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 23 Oct 2018 10:29:22 +0200 Subject: [PATCH 1415/1590] FeinCMS v1.14.3 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index b8bee14f7..64452ceb7 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 14, 2) +VERSION = (1, 14, 3) __version__ = '.'.join(map(str, VERSION)) From 81f690f608311ddabe0baa703b6237db936c25b3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 21 Dec 2018 10:11:15 +0100 Subject: [PATCH 1416/1590] This is still the official location --- feincms/views/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/views/decorators.py b/feincms/views/decorators.py index 365761807..2fab30127 100644 --- a/feincms/views/decorators.py +++ b/feincms/views/decorators.py @@ -6,5 +6,5 @@ from feincms.apps import * warnings.warn( - 'Import ApplicationContent and friends from feincms.apps.', + 'Import ApplicationContent and friends from feincms.content.application.models', DeprecationWarning, stacklevel=2) From 458950f9503a1ac38a441f32bc65552d26dd110f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 21 Dec 2018 10:23:48 +0100 Subject: [PATCH 1417/1590] Allow rendering plugin templates in the context of their parent template --- CHANGELOG.rst | 4 ++++ feincms/models.py | 2 +- feincms/templatetags/feincms_tags.py | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 57ecdc338..0bca657ab 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,10 @@ Change log updated inlines. - Fixed ``TranslatedObjectManager.only_language`` to evaluate callables before filtering. +- Changed the ``render`` protocol of content types to allow returning a + tuple of ``(ct_template, ct_context)`` which works the same way as + `feincms3's template renderers + `__. `v1.14.0`_ (2018-08-16) diff --git a/feincms/models.py b/feincms/models.py index c99c295cb..0e3d49b2c 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -2,7 +2,7 @@ This is the core of FeinCMS All models defined here are abstract, which means no tables are created in -the feincms\_ namespace. +the feincms namespace. """ from __future__ import absolute_import, unicode_literals diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 3b71011bf..a0de9da09 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -9,6 +9,7 @@ import django from django import template from django.conf import settings +from django.template.engine import Engine from django.utils.safestring import mark_safe from feincms.utils import get_singleton, get_singleton_url @@ -37,6 +38,25 @@ def _render_content(content, **kwargs): r = content.render(**kwargs) + if isinstance(r, (list, tuple)): + # Modeled after feincms3's TemplatePluginRenderer + context = kwargs["context"] + plugin_template, plugin_context = r + + if not hasattr(plugin_template, "render"): # Quacks like a template? + try: + engine = context.template.engine + except AttributeError: + engine = Engine.get_default() + + if isinstance(plugin_template, (list, tuple)): + plugin_template = engine.select_template(plugin_template) + else: + plugin_template = engine.get_template(plugin_template) + + with context.push(plugin_context): + return plugin_template.render(context) + if request is not None: level = getattr(request, 'feincms_render_level', 1) setattr(request, 'feincms_render_level', max(level - 1, 0)) From 15a3ac899da948041436dd456d586008197c12a7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 21 Dec 2018 10:28:22 +0100 Subject: [PATCH 1418/1590] Late import for Django 1.7 compatibility --- feincms/templatetags/feincms_tags.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index a0de9da09..1450d7ace 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -9,7 +9,6 @@ import django from django import template from django.conf import settings -from django.template.engine import Engine from django.utils.safestring import mark_safe from feincms.utils import get_singleton, get_singleton_url @@ -47,6 +46,11 @@ def _render_content(content, **kwargs): try: engine = context.template.engine except AttributeError: + # This fails hard in Django 1.7 (ImportError). So what. This + # just means that this particular feature isn't available + # there. + from django.template.engine import Engine + engine = Engine.get_default() if isinstance(plugin_template, (list, tuple)): From 435e462d85d1f6ba3f598e97b2110b9f29a17d83 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 21 Dec 2018 10:31:35 +0100 Subject: [PATCH 1419/1590] Add migrations so that test models are created _after_ e.g. sites.Site --- setup.cfg | 2 +- tests/testapp/migrations/0001_initial.py | 85 ++++++++++++++++++++++++ tests/testapp/migrations/__init__.py | 0 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 tests/testapp/migrations/0001_initial.py create mode 100644 tests/testapp/migrations/__init__.py diff --git a/setup.cfg b/setup.cfg index e0f9c91ef..cc4bd75fa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [flake8] -exclude=venv,.tox,build,docs +exclude=venv,.tox,build,docs,migrations [wheel] universal = 1 diff --git a/tests/testapp/migrations/0001_initial.py b/tests/testapp/migrations/0001_initial.py new file mode 100644 index 000000000..a851c06a8 --- /dev/null +++ b/tests/testapp/migrations/0001_initial.py @@ -0,0 +1,85 @@ +# Generated by Django 2.1.4 on 2018-12-21 09:29 + +from django.db import migrations, models +import django.db.models.deletion +import feincms.extensions.base + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=20)), + ('slug', models.SlugField()), + ('lft', models.PositiveIntegerField(db_index=True, editable=False)), + ('rght', models.PositiveIntegerField(db_index=True, editable=False)), + ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), + ('level', models.PositiveIntegerField(db_index=True, editable=False)), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='testapp.Category')), + ], + options={ + 'verbose_name': 'category', + 'verbose_name_plural': 'categories', + 'ordering': ['tree_id', 'lft'], + }, + ), + migrations.CreateModel( + name='CustomContentType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('region', models.CharField(max_length=255)), + ('ordering', models.IntegerField(default=0, verbose_name='ordering')), + ], + options={ + 'verbose_name': 'custom content type', + 'verbose_name_plural': 'custom content types', + 'db_table': 'testapp_mymodel_customcontenttype', + 'ordering': ['ordering'], + 'permissions': [], + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ExampleCMSBase', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'abstract': False, + }, + bases=(models.Model, feincms.extensions.base.ExtensionsMixin), + ), + migrations.CreateModel( + name='ExampleCMSBase2', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'abstract': False, + }, + bases=(models.Model, feincms.extensions.base.ExtensionsMixin), + ), + migrations.CreateModel( + name='MyModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'abstract': False, + }, + bases=(models.Model, feincms.extensions.base.ExtensionsMixin), + ), + migrations.AddField( + model_name='customcontenttype', + name='parent', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customcontenttype_set', to='testapp.MyModel'), + ), + ] diff --git a/tests/testapp/migrations/__init__.py b/tests/testapp/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb From 93cac884ed88cfc618df5cbe8937b8868275395a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 21 Dec 2018 10:54:47 +0100 Subject: [PATCH 1420/1590] FeinCMS v1.15.0 --- CHANGELOG.rst | 7 ++++++- feincms/__init__.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0bca657ab..ebcfd15bc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,10 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ + +`v1.15.0`_ (2018-12-21) +~~~~~~~~~~~~~~~~~~~~~~~ + - Actually made use of the timeout specified as ``FEINCMS_THUMBNAIL_CACHE_TIMEOUT`` instead of the hardcoded value of seven days. @@ -52,4 +56,5 @@ Change log .. _v1.14.0: https://github.com/feincms/feincms/compare/v1.13.0...v1.14.0 -.. _Next version: https://github.com/feincms/feincms/compare/v1.14.0...master +.. _v1.15.0: https://github.com/feincms/feincms/compare/v1.14.0...v1.15.0 +.. _Next version: https://github.com/feincms/feincms/compare/v1.15.0...master diff --git a/feincms/__init__.py b/feincms/__init__.py index 64452ceb7..c78c98e30 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 14, 3) +VERSION = (1, 15, 0) __version__ = '.'.join(map(str, VERSION)) From 93662596c0d4ba7c8f278d602283bdf848b1f3b1 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Wed, 16 Jan 2019 11:16:45 +0100 Subject: [PATCH 1421/1590] Make the rebuild_mptt management command work with Django 1.11+ --- feincms/management/commands/rebuild_mptt.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index 5e2b2c2cb..b99291d02 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -10,16 +10,22 @@ from __future__ import absolute_import, unicode_literals -from django.core.management.base import NoArgsCommand +try: + from django.core.management.base import NoArgsCommand as BaseCommand +except ImportError: + from django.core.management.base import BaseCommand from feincms.module.page.models import Page -class Command(NoArgsCommand): +class Command(BaseCommand): help = ( "Run this manually to rebuild your mptt pointers. Only use in" " emergencies.") def handle_noargs(self, **options): + self.handle(**options) + + def handle(self, **options): self.stdout.write("Rebuilding MPTT pointers for Page") Page._tree_manager.rebuild() From a3d3d4b49b9a46c9eb093f79b65a113aa8e4f9ae Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 1 Feb 2019 18:19:57 +0100 Subject: [PATCH 1422/1590] Reformat everything using black --- CHANGELOG.rst | 2 + feincms/__init__.py | 19 +- feincms/_internal.py | 28 +- feincms/admin/__init__.py | 10 +- feincms/admin/filters.py | 66 +- feincms/admin/item_editor.py | 139 +- feincms/admin/tree_editor.py | 295 ++-- feincms/content/application/models.py | 219 +-- feincms/content/contactform/__init__.py | 6 +- feincms/content/contactform/models.py | 52 +- feincms/content/file/models.py | 21 +- feincms/content/filer/models.py | 61 +- feincms/content/image/models.py | 51 +- feincms/content/medialibrary/models.py | 6 +- feincms/content/raw/models.py | 6 +- feincms/content/richtext/models.py | 21 +- feincms/content/section/models.py | 75 +- feincms/content/template/models.py | 20 +- feincms/content/video/models.py | 53 +- feincms/context_processors.py | 4 +- feincms/contrib/fields.py | 11 +- feincms/contrib/preview/urls.py | 3 +- feincms/contrib/preview/views.py | 8 +- feincms/contrib/richtext.py | 16 +- feincms/contrib/tagging.py | 59 +- feincms/default_settings.py | 98 +- feincms/extensions/__init__.py | 13 +- feincms/extensions/base.py | 45 +- feincms/extensions/changedate.py | 23 +- feincms/extensions/ct_tracker.py | 54 +- feincms/extensions/datepublisher.py | 75 +- feincms/extensions/featured.py | 13 +- feincms/extensions/seo.py | 43 +- feincms/extensions/translations.py | 125 +- .../commands/medialibrary_orphans.py | 4 +- .../commands/medialibrary_to_filer.py | 28 +- feincms/management/commands/rebuild_mptt.py | 6 +- feincms/models.py | 317 ++-- feincms/module/extensions/changedate.py | 8 +- feincms/module/extensions/ct_tracker.py | 8 +- feincms/module/extensions/datepublisher.py | 8 +- feincms/module/extensions/featured.py | 8 +- feincms/module/extensions/seo.py | 8 +- feincms/module/extensions/translations.py | 8 +- feincms/module/medialibrary/__init__.py | 2 +- feincms/module/medialibrary/contents.py | 33 +- feincms/module/medialibrary/fields.py | 50 +- feincms/module/medialibrary/forms.py | 43 +- feincms/module/medialibrary/modeladmins.py | 154 +- feincms/module/medialibrary/models.py | 154 +- feincms/module/medialibrary/thumbnail.py | 9 +- feincms/module/medialibrary/zip.py | 99 +- feincms/module/mixins.py | 38 +- feincms/module/page/admin.py | 2 +- feincms/module/page/extensions/excerpt.py | 17 +- feincms/module/page/extensions/navigation.py | 56 +- .../page/extensions/navigationgroups.py | 21 +- .../module/page/extensions/relatedpages.py | 24 +- feincms/module/page/extensions/sites.py | 18 +- feincms/module/page/extensions/symlinks.py | 29 +- feincms/module/page/extensions/titles.py | 48 +- feincms/module/page/forms.py | 155 +- feincms/module/page/modeladmins.py | 173 +- feincms/module/page/models.py | 164 +- feincms/module/page/processors.py | 54 +- feincms/module/page/sitemap.py | 35 +- feincms/shortcuts.py | 2 +- .../templatetags/applicationcontent_tags.py | 41 +- feincms/templatetags/feincms_admin_tags.py | 35 +- feincms/templatetags/feincms_page_tags.py | 142 +- feincms/templatetags/feincms_tags.py | 32 +- feincms/templatetags/feincms_thumbnail.py | 108 +- feincms/templatetags/fragment_tags.py | 25 +- feincms/translations.py | 96 +- feincms/urls.py | 4 +- feincms/utils/__init__.py | 51 +- feincms/utils/queryset_transform.py | 15 +- feincms/utils/templatetags.py | 31 +- feincms/views/__init__.py | 27 +- feincms/views/decorators.py | 6 +- setup.cfg | 5 +- setup.py | 70 +- tests/manage.py | 3 +- tests/testapp/applicationcontent_urls.py | 45 +- tests/testapp/context_processors.py | 2 +- tests/testapp/migrations/0001_initial.py | 130 +- tests/testapp/models.py | 106 +- tests/testapp/navigation_extensions.py | 9 +- tests/testapp/settings.py | 99 +- tests/testapp/tests/test_cms.py | 55 +- tests/testapp/tests/test_extensions.py | 70 +- tests/testapp/tests/test_page.py | 1480 ++++++++--------- tests/testapp/tests/test_stuff.py | 42 +- tests/testapp/tests/utils.py | 2 + tests/testapp/urls.py | 21 +- tox.ini | 2 + 96 files changed, 3296 insertions(+), 2981 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ebcfd15bc..5a54bc50d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,8 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ +- Reformatted everything using black. + `v1.15.0`_ (2018-12-21) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/feincms/__init__.py b/feincms/__init__.py index c78c98e30..308b8f1cd 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, unicode_literals VERSION = (1, 15, 0) -__version__ = '.'.join(map(str, VERSION)) +__version__ = ".".join(map(str, VERSION)) class LazySettings(object): @@ -10,7 +10,7 @@ def _load_settings(self): from django.conf import settings as django_settings for key in dir(default_settings): - if not key.startswith('FEINCMS_'): + if not key.startswith("FEINCMS_"): continue value = getattr(default_settings, key) @@ -46,6 +46,7 @@ def ensure_completely_loaded(force=False): return True from django.apps import apps + if not apps.ready: return @@ -61,13 +62,17 @@ def ensure_completely_loaded(force=False): import django from distutils.version import LooseVersion - if LooseVersion(django.get_version()) < LooseVersion('1.8'): + if LooseVersion(django.get_version()) < LooseVersion("1.8"): for model in apps.get_models(): for cache_name in ( - '_field_cache', '_field_name_cache', '_m2m_cache', - '_related_objects_cache', '_related_many_to_many_cache', - '_name_map'): + "_field_cache", + "_field_name_cache", + "_m2m_cache", + "_related_objects_cache", + "_related_many_to_many_cache", + "_name_map", + ): try: delattr(model._meta, cache_name) except AttributeError: @@ -85,7 +90,7 @@ def ensure_completely_loaded(force=False): # get_models cache again here. If we don't do this, Django 1.5 chokes # on a model validation error (Django 1.4 doesn't exhibit this # problem). See Issue #323 on github. - if hasattr(apps, 'cache'): + if hasattr(apps, "cache"): apps.cache.get_models.cache_clear() if apps.ready: diff --git a/feincms/_internal.py b/feincms/_internal.py index 134046da1..44a669748 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -11,9 +11,7 @@ from django.template.loader import render_to_string -__all__ = ( - 'monkeypatch_method', 'monkeypatch_property', -) +__all__ = ("monkeypatch_method", "monkeypatch_property") def monkeypatch_method(cls): @@ -28,6 +26,7 @@ def (self, [...]): def decorator(func): setattr(cls, func.__name__, func) return func + return decorator @@ -43,24 +42,23 @@ def (self, [...]): def decorator(func): setattr(cls, func.__name__, property(func)) return func + return decorator -if LooseVersion(get_version()) < LooseVersion('1.10'): +if LooseVersion(get_version()) < LooseVersion("1.10"): + def ct_render_to_string(template, ctx, **kwargs): from django.template import RequestContext - context_instance = kwargs.get('context') - if context_instance is None and kwargs.get('request'): - context_instance = RequestContext(kwargs['request']) + context_instance = kwargs.get("context") + if context_instance is None and kwargs.get("request"): + context_instance = RequestContext(kwargs["request"]) + + return render_to_string(template, ctx, context_instance=context_instance) + - return render_to_string( - template, - ctx, - context_instance=context_instance) else: + def ct_render_to_string(template, ctx, **kwargs): - return render_to_string( - template, - ctx, - request=kwargs.get('request')) + return render_to_string(template, ctx, request=kwargs.get("request")) diff --git a/feincms/admin/__init__.py b/feincms/admin/__init__.py index 0a2edfe1f..9008a9982 100644 --- a/feincms/admin/__init__.py +++ b/feincms/admin/__init__.py @@ -5,10 +5,12 @@ FieldListFilter.register( - lambda f: getattr(f, 'parent_filter', False), + lambda f: getattr(f, "parent_filter", False), ParentFieldListFilter, - take_priority=True) + take_priority=True, +) FieldListFilter.register( - lambda f: getattr(f, 'category_filter', False), + lambda f: getattr(f, "category_filter", False), CategoryFieldListFilter, - take_priority=True) + take_priority=True, +) diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index cb3187ded..75a1a73c2 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -26,38 +26,44 @@ class ParentFieldListFilter(ChoicesFieldListFilter): my_model_field.page_parent_filter = True """ - def __init__(self, f, request, params, model, model_admin, - field_path=None): + def __init__(self, f, request, params, model, model_admin, field_path=None): super(ParentFieldListFilter, self).__init__( - f, request, params, model, model_admin, field_path) + f, request, params, model, model_admin, field_path + ) - parent_ids = model.objects.exclude(parent=None).values_list( - "parent__id", flat=True).order_by("parent__id").distinct() + parent_ids = ( + model.objects.exclude(parent=None) + .values_list("parent__id", flat=True) + .order_by("parent__id") + .distinct() + ) parents = model.objects.filter(pk__in=parent_ids).values_list( - "pk", "title", "level") - self.lookup_choices = [( - pk, - "%s%s" % ( - "  " * level, - shorten_string(title, max_length=25)), - ) for pk, title, level in parents] + "pk", "title", "level" + ) + self.lookup_choices = [ + ( + pk, + "%s%s" % ("  " * level, shorten_string(title, max_length=25)), + ) + for pk, title, level in parents + ] def choices(self, cl): yield { - 'selected': self.lookup_val is None, - 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), - 'display': _('All') + "selected": self.lookup_val is None, + "query_string": cl.get_query_string({}, [self.lookup_kwarg]), + "display": _("All"), } for pk, title in self.lookup_choices: yield { - 'selected': pk == int(self.lookup_val or '0'), - 'query_string': cl.get_query_string({self.lookup_kwarg: pk}), - 'display': mark_safe(smart_text(title)) + "selected": pk == int(self.lookup_val or "0"), + "query_string": cl.get_query_string({self.lookup_kwarg: pk}), + "display": mark_safe(smart_text(title)), } def title(self): - return _('Parent') + return _("Parent") class CategoryFieldListFilter(ChoicesFieldListFilter): @@ -67,10 +73,10 @@ class CategoryFieldListFilter(ChoicesFieldListFilter): my_model_field.category_filter = True """ - def __init__(self, f, request, params, model, model_admin, - field_path=None): + def __init__(self, f, request, params, model, model_admin, field_path=None): super(CategoryFieldListFilter, self).__init__( - f, request, params, model, model_admin, field_path) + f, request, params, model, model_admin, field_path + ) # Restrict results to categories which are actually in use: if DJANGO_VERSION < (1, 8): @@ -85,7 +91,7 @@ def __init__(self, f, request, params, model, model_admin, self.lookup_choices = sorted( [ - (i.pk, '%s (%s)' % (i, i._related_count)) + (i.pk, "%s (%s)" % (i, i._related_count)) for i in related_model.objects.annotate( _related_count=Count(related_name) ).exclude(_related_count=0) @@ -95,17 +101,17 @@ def __init__(self, f, request, params, model, model_admin, def choices(self, cl): yield { - 'selected': self.lookup_val is None, - 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), - 'display': _('All') + "selected": self.lookup_val is None, + "query_string": cl.get_query_string({}, [self.lookup_kwarg]), + "display": _("All"), } for pk, title in self.lookup_choices: yield { - 'selected': pk == int(self.lookup_val or '0'), - 'query_string': cl.get_query_string({self.lookup_kwarg: pk}), - 'display': mark_safe(smart_text(title)) + "selected": pk == int(self.lookup_val or "0"), + "query_string": cl.get_query_string({self.lookup_kwarg: pk}), + "display": mark_safe(smart_text(title)), } def title(self): - return _('Category') + return _("Category") diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 051265f6e..9e9fc696b 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -20,8 +20,8 @@ # ------------------------------------------------------------------------ -FEINCMS_CONTENT_FIELDSET_NAME = 'FEINCMS_CONTENT' -FEINCMS_CONTENT_FIELDSET = (FEINCMS_CONTENT_FIELDSET_NAME, {'fields': ()}) +FEINCMS_CONTENT_FIELDSET_NAME = "FEINCMS_CONTENT" +FEINCMS_CONTENT_FIELDSET = (FEINCMS_CONTENT_FIELDSET_NAME, {"fields": ()}) logger = logging.getLogger(__name__) @@ -45,11 +45,11 @@ class FeinCMSInline(InlineModelAdmin): form = ItemEditorForm extra = 0 - fk_name = 'parent' + fk_name = "parent" if VERSION < (2, 1): - template = 'admin/feincms/content_inline_dj20.html' + template = "admin/feincms/content_inline_dj20.html" else: - template = 'admin/feincms/content_inline.html' + template = "admin/feincms/content_inline.html" # ------------------------------------------------------------------------ @@ -70,7 +70,8 @@ def __init__(self, model, admin_site): def get_inline_instances(self, request, *args, **kwargs): inline_instances = super(ItemEditor, self).get_inline_instances( - request, *args, **kwargs) + request, *args, **kwargs + ) self.append_feincms_inlines(inline_instances, request) return inline_instances @@ -83,9 +84,12 @@ def append_feincms_inlines(self, inline_instances, request): inline_instances.append(inline_instance) def can_add_content(self, request, content_type): - perm = '.'.join(( - content_type._meta.app_label, - get_permission_codename('add', content_type._meta))) + perm = ".".join( + ( + content_type._meta.app_label, + get_permission_codename("add", content_type._meta), + ) + ) return request.user.has_perm(perm) def get_feincms_inlines(self, model, request): @@ -97,27 +101,26 @@ def get_feincms_inlines(self, model, request): if not self.can_add_content(request, content_type): continue - attrs = { - '__module__': model.__module__, - 'model': content_type, - } + attrs = {"__module__": model.__module__, "model": content_type} - if hasattr(content_type, 'feincms_item_editor_inline'): + if hasattr(content_type, "feincms_item_editor_inline"): inline = content_type.feincms_item_editor_inline - attrs['form'] = inline.form + attrs["form"] = inline.form - if hasattr(content_type, 'feincms_item_editor_form'): + if hasattr(content_type, "feincms_item_editor_form"): warnings.warn( - 'feincms_item_editor_form on %s is ignored because ' - 'feincms_item_editor_inline is set too' % content_type, - RuntimeWarning) + "feincms_item_editor_form on %s is ignored because " + "feincms_item_editor_inline is set too" % content_type, + RuntimeWarning, + ) else: inline = FeinCMSInline - attrs['form'] = getattr( - content_type, 'feincms_item_editor_form', inline.form) + attrs["form"] = getattr( + content_type, "feincms_item_editor_form", inline.form + ) - name = '%sFeinCMSInline' % content_type.__name__ + name = "%sFeinCMSInline" % content_type.__name__ # TODO: We generate a new class every time. Is that really wanted? inline_class = type(str(name), (inline,), attrs) inlines.append(inline_class) @@ -129,21 +132,19 @@ def get_content_type_map(self, request): for content_type in self.model._feincms_content_types: if self.model == content_type._feincms_content_class: content_name = content_type._meta.verbose_name - content_types.append( - (content_name, content_type.__name__.lower())) + content_types.append((content_name, content_type.__name__.lower())) return content_types def get_extra_context(self, request): """ Return extra context parameters for add/change views. """ extra_context = { - 'request': request, - 'model': self.model, - 'available_templates': getattr( - self.model, '_feincms_templates', ()), - 'has_parent_attribute': hasattr(self.model, 'parent'), - 'content_types': self.get_content_type_map(request), - 'FEINCMS_CONTENT_FIELDSET_NAME': FEINCMS_CONTENT_FIELDSET_NAME, + "request": request, + "model": self.model, + "available_templates": getattr(self.model, "_feincms_templates", ()), + "has_parent_attribute": hasattr(self.model, "parent"), + "content_types": self.get_content_type_map(request), + "FEINCMS_CONTENT_FIELDSET_NAME": FEINCMS_CONTENT_FIELDSET_NAME, } for processor in self.model.feincms_item_editor_context_processors: @@ -154,9 +155,7 @@ def get_extra_context(self, request): def add_view(self, request, **kwargs): if not self.has_add_permission(request): logger.warning( - "Denied adding %s to \"%s\" (no add permission)", - self.model, - request.user + 'Denied adding %s to "%s" (no add permission)', self.model, request.user ) raise Http404 @@ -164,64 +163,60 @@ def add_view(self, request, **kwargs): # insert dummy object as 'original' so template code can grab defaults # for template, etc. - context['original'] = self.model() + context["original"] = self.model() # If there are errors in the form, we need to preserve the object's # template as it was set when the user attempted to save it, so that # the same regions appear on screen. - if request.method == 'POST' and \ - hasattr(self.model, '_feincms_templates'): - context['original'].template_key = request.POST['template_key'] + if request.method == "POST" and hasattr(self.model, "_feincms_templates"): + context["original"].template_key = request.POST["template_key"] context.update(self.get_extra_context(request)) - context.update(kwargs.get('extra_context', {})) - kwargs['extra_context'] = context + context.update(kwargs.get("extra_context", {})) + kwargs["extra_context"] = context return super(ItemEditor, self).add_view(request, **kwargs) def render_change_form(self, request, context, **kwargs): - if kwargs.get('add'): - if request.method == 'GET' and 'adminform' in context: - if 'template_key' in context['adminform'].form.initial: - context['original'].template_key = ( - context['adminform'].form.initial['template_key']) + if kwargs.get("add"): + if request.method == "GET" and "adminform" in context: + if "template_key" in context["adminform"].form.initial: + context["original"].template_key = context[ + "adminform" + ].form.initial["template_key"] # ensure that initially-selected template in form is also # used to render the initial regions in the item editor - return super( - ItemEditor, self).render_change_form(request, context, **kwargs) + return super(ItemEditor, self).render_change_form(request, context, **kwargs) def change_view(self, request, object_id, **kwargs): obj = self.get_object(request, unquote(object_id)) if not self.has_change_permission(request, obj): logger.warning( - "Denied editing %s to \"%s\" (no edit permission)", + 'Denied editing %s to "%s" (no edit permission)', self.model, - request.user + request.user, ) raise Http404 context = {} context.update(self.get_extra_context(request)) - context.update(kwargs.get('extra_context', {})) - kwargs['extra_context'] = context - return super(ItemEditor, self).change_view( - request, object_id, **kwargs) + context.update(kwargs.get("extra_context", {})) + kwargs["extra_context"] = context + return super(ItemEditor, self).change_view(request, object_id, **kwargs) def save_related(self, request, form, formsets, change): - super(ItemEditor, self).save_related( - request, form, formsets, change) + super(ItemEditor, self).save_related(request, form, formsets, change) itemeditor_post_save_related.send( - sender=form.instance.__class__, - instance=form.instance, - created=not change) + sender=form.instance.__class__, instance=form.instance, created=not change + ) @property def change_form_template(self): opts = self.model._meta return [ - 'admin/feincms/%s/%s/item_editor.html' % ( - opts.app_label, opts.object_name.lower()), - 'admin/feincms/%s/item_editor.html' % opts.app_label, - 'admin/feincms/item_editor.html', + "admin/feincms/%s/%s/item_editor.html" + % (opts.app_label, opts.object_name.lower()), + "admin/feincms/%s/item_editor.html" % opts.app_label, + "admin/feincms/item_editor.html", ] def get_fieldsets(self, request, obj=None): @@ -230,9 +225,7 @@ def get_fieldsets(self, request, obj=None): Is it reasonable to assume this should always be included? """ - fieldsets = copy.deepcopy( - super(ItemEditor, self).get_fieldsets(request, obj) - ) + fieldsets = copy.deepcopy(super(ItemEditor, self).get_fieldsets(request, obj)) names = [f[0] for f in fieldsets] if FEINCMS_CONTENT_FIELDSET_NAME not in names: @@ -247,16 +240,20 @@ def get_fieldsets(self, request, obj=None): recover_form_template = "admin/feincms/recover_form.html" # For Reversion < v2.0.0 - def render_revision_form(self, request, obj, version, context, - revert=False, recover=False): + def render_revision_form( + self, request, obj, version, context, revert=False, recover=False + ): context.update(self.get_extra_context(request)) return super(ItemEditor, self).render_revision_form( - request, obj, version, context, revert, recover) + request, obj, version, context, revert, recover + ) # For Reversion >= v2.0.0 - def _reversion_revisionform_view(self, request, version, template_name, - extra_context=None): + def _reversion_revisionform_view( + self, request, version, template_name, extra_context=None + ): context = extra_context or {} context.update(self.get_extra_context(request)) return super(ItemEditor, self)._reversion_revisionform_view( - request, version, template_name, context) + request, version, template_name, context + ) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index bff48fa40..2eecb1484 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -14,8 +14,12 @@ from django.contrib.staticfiles.templatetags.staticfiles import static from django.db.models import Q from django.http import ( - HttpResponse, HttpResponseBadRequest, - HttpResponseForbidden, HttpResponseNotFound, HttpResponseServerError) + HttpResponse, + HttpResponseBadRequest, + HttpResponseForbidden, + HttpResponseNotFound, + HttpResponseServerError, +) from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _, ugettext @@ -38,15 +42,14 @@ def django_boolean_icon(field_val, alt_text=None, title=None): """ # Origin: contrib/admin/templatetags/admin_list.py - BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'} + BOOLEAN_MAPPING = {True: "yes", False: "no", None: "unknown"} alt_text = alt_text or BOOLEAN_MAPPING[field_val] if title is not None: title = 'title="%s" ' % title else: - title = '' - icon_url = static('feincms/img/icon-%s.gif' % BOOLEAN_MAPPING[field_val]) - return mark_safe( - '%s' % (icon_url, alt_text, title)) + title = "" + icon_url = static("feincms/img/icon-%s.gif" % BOOLEAN_MAPPING[field_val]) + return mark_safe('%s' % (icon_url, alt_text, title)) def _build_tree_structure(queryset): @@ -64,23 +67,16 @@ def _build_tree_structure(queryset): all_nodes = {} mptt_opts = queryset.model._mptt_meta - items = queryset.order_by( - mptt_opts.tree_id_attr, - mptt_opts.left_attr, - ).values_list( - "pk", - "%s_id" % mptt_opts.parent_attr, + items = queryset.order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr).values_list( + "pk", "%s_id" % mptt_opts.parent_attr ) for p_id, parent_id in items: - all_nodes.setdefault( - str(parent_id) if parent_id else 0, - [], - ).append(p_id) + all_nodes.setdefault(str(parent_id) if parent_id else 0, []).append(p_id) return all_nodes # ------------------------------------------------------------------------ -def ajax_editable_boolean_cell(item, attr, text='', override=None): +def ajax_editable_boolean_cell(item, attr, text="", override=None): """ Generate a html snippet for showing a boolean value on the admin page. Item is an object, attr is the attribute name we should display. Text @@ -95,7 +91,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): (useful for "disabled and you can't change it" situations). """ if text: - text = ' (%s)' % text + text = " (%s)" % text if override is not None: a = [django_boolean_icon(override, text), text] @@ -103,15 +99,13 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None): value = getattr(item, attr) a = [ '' % ( - item.pk, - attr, - 'checked="checked"' if value else '', - )] + ' data-inplace-attribute="%s" %s>' + % (item.pk, attr, 'checked="checked"' if value else "") + ] a.insert(0, '
    ' % (attr, item.pk)) - a.append('
    ') - return mark_safe(''.join(a)) + a.append("
    ") + return mark_safe("".join(a)) # ------------------------------------------------------------------------ @@ -127,8 +121,10 @@ class MyTreeEditor(TreeEditor): active_toggle = ajax_editable_boolean('active', _('is active')) """ + def _fn(self, item): return ajax_editable_boolean_cell(item, attr) + _fn.short_description = short_description _fn.editable_boolean_field = attr return _fn @@ -147,8 +143,11 @@ def __init__(self, request, *args, **kwargs): def get_queryset(self, *args, **kwargs): mptt_opts = self.model._mptt_meta - qs = super(ChangeList, self).get_queryset(*args, **kwargs).\ - order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr) + qs = ( + super(ChangeList, self) + .get_queryset(*args, **kwargs) + .order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr) + ) # Force has_filters, so that the expand/collapse in sidebar is visible self.has_filters = True return qs @@ -157,14 +156,15 @@ def get_results(self, request): mptt_opts = self.model._mptt_meta if settings.FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS: clauses = [ - Q(**{ - mptt_opts.tree_id_attr: tree_id, - mptt_opts.left_attr + '__lte': lft, - mptt_opts.right_attr + '__gte': rght, - }) for lft, rght, tree_id in self.queryset.values_list( - mptt_opts.left_attr, - mptt_opts.right_attr, - mptt_opts.tree_id_attr, + Q( + **{ + mptt_opts.tree_id_attr: tree_id, + mptt_opts.left_attr + "__lte": lft, + mptt_opts.right_attr + "__gte": rght, + } + ) + for lft, rght, tree_id in self.queryset.values_list( + mptt_opts.left_attr, mptt_opts.right_attr, mptt_opts.tree_id_attr ) ] # We could optimise a bit here by explicitely filtering out @@ -177,7 +177,7 @@ def get_results(self, request): # clauses if the initial query set is unfiltered. This # is good. self.queryset |= self.model._default_manager.filter( - reduce(lambda p, q: p | q, clauses), + reduce(lambda p, q: p | q, clauses) ) super(ChangeList, self).get_results(request) @@ -186,11 +186,13 @@ def get_results(self, request): # which is not passed in later stages in the tree editor for item in self.result_list: item.feincms_changeable = self.model_admin.has_change_permission( - request, item) + request, item + ) item.feincms_addable = ( - item.feincms_changeable and - self.model_admin.has_add_permission(request, item)) + item.feincms_changeable + and self.model_admin.has_add_permission(request, item) + ) # ------------------------------------------------------------------------ @@ -215,29 +217,32 @@ def __init__(self, *args, **kwargs): self.list_display = list(self.list_display) - if 'indented_short_title' not in self.list_display: - if self.list_display[0] == 'action_checkbox': - self.list_display[1] = 'indented_short_title' + if "indented_short_title" not in self.list_display: + if self.list_display[0] == "action_checkbox": + self.list_display[1] = "indented_short_title" else: - self.list_display[0] = 'indented_short_title' - self.list_display_links = ('indented_short_title',) + self.list_display[0] = "indented_short_title" + self.list_display_links = ("indented_short_title",) opts = self.model._meta self.change_list_template = [ - 'admin/feincms/%s/%s/tree_editor.html' % ( - opts.app_label, opts.object_name.lower()), - 'admin/feincms/%s/tree_editor.html' % opts.app_label, - 'admin/feincms/tree_editor.html', + "admin/feincms/%s/%s/tree_editor.html" + % (opts.app_label, opts.object_name.lower()), + "admin/feincms/%s/tree_editor.html" % opts.app_label, + "admin/feincms/tree_editor.html", ] - self.object_change_permission =\ - opts.app_label + '.' + get_permission_codename('change', opts) - self.object_add_permission =\ - opts.app_label + '.' + get_permission_codename('add', opts) - self.object_delete_permission =\ - opts.app_label + '.' + get_permission_codename('delete', opts) + self.object_change_permission = ( + opts.app_label + "." + get_permission_codename("change", opts) + ) + self.object_add_permission = ( + opts.app_label + "." + get_permission_codename("add", opts) + ) + self.object_delete_permission = ( + opts.app_label + "." + get_permission_codename("delete", opts) + ) def changeable(self, item): - return getattr(item, 'feincms_changeable', True) + return getattr(item, "feincms_changeable", True) def indented_short_title(self, item): """ @@ -245,7 +250,7 @@ def indented_short_title(self, item): the object's depth in the hierarchy. """ mptt_opts = item._mptt_meta - r = '' + r = "" try: url = item.get_absolute_url() except (AttributeError,): @@ -254,31 +259,35 @@ def indented_short_title(self, item): if url: r = ( '') % (url, item.pk) + ' value="%s" id="_refkey_%d" />' + ) % (url, item.pk) - changeable_class = '' + changeable_class = "" if not self.changeable(item): - changeable_class = ' tree-item-not-editable' - tree_root_class = '' + changeable_class = " tree-item-not-editable" + tree_root_class = "" if not item.parent_id: - tree_root_class = ' tree-root' + tree_root_class = " tree-root" r += ( '  ') % ( + ' style="width: %dpx;">  ' + ) % ( item.pk, changeable_class, tree_root_class, - 14 + getattr(item, mptt_opts.level_attr) * 18) + 14 + getattr(item, mptt_opts.level_attr) * 18, + ) -# r += '' - if hasattr(item, 'short_title') and callable(item.short_title): + # r += '' + if hasattr(item, "short_title") and callable(item.short_title): r += escape(item.short_title()) else: - r += escape('%s' % item) -# r += '' + r += escape("%s" % item) + # r += '' return mark_safe(r) - indented_short_title.short_description = _('title') + + indented_short_title.short_description = _("title") def _collect_editable_booleans(self): """ @@ -286,7 +295,7 @@ def _collect_editable_booleans(self): want the user to be able to edit arbitrary fields by crafting an AJAX request by hand. """ - if hasattr(self, '_ajax_editable_booleans'): + if hasattr(self, "_ajax_editable_booleans"): return self._ajax_editable_booleans = {} @@ -299,14 +308,17 @@ def _collect_editable_booleans(self): except (AttributeError, TypeError): continue - attr = getattr(item, 'editable_boolean_field', None) + attr = getattr(item, "editable_boolean_field", None) if attr: - if hasattr(item, 'editable_boolean_result'): + if hasattr(item, "editable_boolean_result"): result_func = item.editable_boolean_result else: + def _fn(attr): return lambda self, instance: [ - ajax_editable_boolean_cell(instance, attr)] + ajax_editable_boolean_cell(instance, attr) + ] + result_func = _fn(attr) self._ajax_editable_booleans[attr] = result_func @@ -315,17 +327,22 @@ def _toggle_boolean(self, request): Handle an AJAX toggle_boolean request """ try: - item_id = int(request.POST.get('item_id', None)) - attr = str(request.POST.get('attr', None)) + item_id = int(request.POST.get("item_id", None)) + attr = str(request.POST.get("attr", None)) except Exception: return HttpResponseBadRequest("Malformed request") if not request.user.is_staff: logger.warning( - "Denied AJAX request by non-staff \"%s\" to toggle boolean" - " %s for object #%s", request.user, attr, item_id) + 'Denied AJAX request by non-staff "%s" to toggle boolean' + " %s for object #%s", + request.user, + attr, + item_id, + ) return HttpResponseForbidden( - _("You do not have permission to modify this object")) + _("You do not have permission to modify this object") + ) self._collect_editable_booleans() @@ -339,15 +356,24 @@ def _toggle_boolean(self, request): if not self.has_change_permission(request, obj=obj): logger.warning( - "Denied AJAX request by \"%s\" to toggle boolean %s for" - " object %s", request.user, attr, item_id) + 'Denied AJAX request by "%s" to toggle boolean %s for' " object %s", + request.user, + attr, + item_id, + ) return HttpResponseForbidden( - _("You do not have permission to modify this object")) + _("You do not have permission to modify this object") + ) new_state = not getattr(obj, attr) logger.info( - "Toggle %s on #%d %s to %s by \"%s\"", - attr, obj.pk, obj, "on" if new_state else "off", request.user) + 'Toggle %s on #%d %s to %s by "%s"', + attr, + obj.pk, + obj, + "on" if new_state else "off", + request.user, + ) try: before_data = self._ajax_editable_booleans[attr](self, obj) @@ -359,17 +385,16 @@ def _toggle_boolean(self, request): data = self._ajax_editable_booleans[attr](self, obj) except Exception: - logger.exception( - "Unhandled exception while toggling %s on %s", attr, obj) - return HttpResponseServerError( - "Unable to toggle %s on %s" % (attr, obj)) + logger.exception("Unhandled exception while toggling %s on %s", attr, obj) + return HttpResponseServerError("Unable to toggle %s on %s" % (attr, obj)) # Weed out unchanged cells to keep the updates small. This assumes # that the order a possible get_descendents() returns does not change # before and after toggling this attribute. Unlikely, but still... return HttpResponse( json.dumps([b for a, b in zip(before_data, data) if a != b]), - content_type="application/json") + content_type="application/json", + ) def get_changelist(self, request, **kwargs): return ChangeList @@ -380,30 +405,36 @@ def changelist_view(self, request, extra_context=None, *args, **kwargs): change list/actions page. """ - if 'actions_column' not in self.list_display: - self.list_display.append('actions_column') + if "actions_column" not in self.list_display: + self.list_display.append("actions_column") # handle common AJAX requests if request.is_ajax(): - cmd = request.POST.get('__cmd') - if cmd == 'toggle_boolean': + cmd = request.POST.get("__cmd") + if cmd == "toggle_boolean": return self._toggle_boolean(request) - elif cmd == 'move_node': + elif cmd == "move_node": return self._move_node(request) - return HttpResponseBadRequest('Oops. AJAX request not understood.') + return HttpResponseBadRequest("Oops. AJAX request not understood.") extra_context = extra_context or {} - extra_context['tree_structure'] = mark_safe( - json.dumps(_build_tree_structure(self.get_queryset(request)))) - extra_context['node_levels'] = mark_safe(json.dumps( - dict(self.get_queryset(request).order_by().values_list( - 'pk', self.model._mptt_meta.level_attr - )) - )) + extra_context["tree_structure"] = mark_safe( + json.dumps(_build_tree_structure(self.get_queryset(request))) + ) + extra_context["node_levels"] = mark_safe( + json.dumps( + dict( + self.get_queryset(request) + .order_by() + .values_list("pk", self.model._mptt_meta.level_attr) + ) + ) + ) return super(TreeEditor, self).changelist_view( - request, extra_context, *args, **kwargs) + request, extra_context, *args, **kwargs + ) def has_add_permission(self, request, obj=None): """ @@ -429,8 +460,7 @@ def has_change_permission(self, request, obj=None): else: r = request.user.has_perm(perm) - return r and super(TreeEditor, self).has_change_permission( - request, obj) + return r and super(TreeEditor, self).has_change_permission(request, obj) def has_delete_permission(self, request, obj=None): """ @@ -443,30 +473,29 @@ def has_delete_permission(self, request, obj=None): else: r = request.user.has_perm(perm) - return r and super(TreeEditor, self).has_delete_permission( - request, obj) + return r and super(TreeEditor, self).has_delete_permission(request, obj) def _move_node(self, request): - if hasattr(self.model.objects, 'move_node'): + if hasattr(self.model.objects, "move_node"): tree_manager = self.model.objects else: tree_manager = self.model._tree_manager queryset = self.get_queryset(request) - cut_item = queryset.get(pk=request.POST.get('cut_item')) - pasted_on = queryset.get(pk=request.POST.get('pasted_on')) - position = request.POST.get('position') + cut_item = queryset.get(pk=request.POST.get("cut_item")) + pasted_on = queryset.get(pk=request.POST.get("pasted_on")) + position = request.POST.get("position") if not self.has_change_permission(request, cut_item): - self.message_user(request, _('No permission')) - return HttpResponse('FAIL') + self.message_user(request, _("No permission")) + return HttpResponse("FAIL") - if position in ('last-child', 'left', 'right'): + if position in ("last-child", "left", "right"): try: tree_manager.move_node(cut_item, pasted_on, position) except InvalidMove as e: - self.message_user(request, '%s' % e) - return HttpResponse('FAIL') + self.message_user(request, "%s" % e) + return HttpResponse("FAIL") # Ensure that model save methods have been run (required to # update Page._cached_url values, might also be helpful for other @@ -475,12 +504,12 @@ def _move_node(self, request): item.save() self.message_user( - request, - ugettext('%s has been moved to a new position.') % cut_item) - return HttpResponse('OK') + request, ugettext("%s has been moved to a new position.") % cut_item + ) + return HttpResponse("OK") - self.message_user(request, _('Did not understand moving instruction.')) - return HttpResponse('FAIL') + self.message_user(request, _("Did not understand moving instruction.")) + return HttpResponse("FAIL") def _actions_column(self, instance): if self.changeable(instance): @@ -488,8 +517,9 @@ def _actions_column(self, instance): return [] def actions_column(self, instance): - return mark_safe(' '.join(self._actions_column(instance))) - actions_column.short_description = _('actions') + return mark_safe(" ".join(self._actions_column(instance))) + + actions_column.short_description = _("actions") def delete_selected_tree(self, modeladmin, request, queryset): """ @@ -498,7 +528,7 @@ def delete_selected_tree(self, modeladmin, request, queryset): trigger the post_delete hooks.) """ # If this is True, the confirmation page has been displayed - if request.POST.get('post'): + if request.POST.get("post"): n = 0 # TODO: The disable_mptt_updates / rebuild is a work around # for what seems to be a mptt problem when deleting items @@ -512,13 +542,15 @@ def delete_selected_tree(self, modeladmin, request, queryset): self.log_deletion(request, obj, obj_display) else: logger.warning( - "Denied delete request by \"%s\" for object #%s", - request.user, obj.id) + 'Denied delete request by "%s" for object #%s', + request.user, + obj.id, + ) if n > 0: queryset.model.objects.rebuild() self.message_user( - request, - _("Successfully deleted %(count)d items.") % {"count": n}) + request, _("Successfully deleted %(count)d items.") % {"count": n} + ) # Return None to display the change list page again return None else: @@ -527,9 +559,10 @@ def delete_selected_tree(self, modeladmin, request, queryset): def get_actions(self, request): actions = super(TreeEditor, self).get_actions(request) - if 'delete_selected' in actions: - actions['delete_selected'] = ( + if "delete_selected" in actions: + actions["delete_selected"] = ( self.delete_selected_tree, - 'delete_selected', - _("Delete selected %(verbose_name_plural)s")) + "delete_selected", + _("Delete selected %(verbose_name_plural)s"), + ) return actions diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index d872b1731..1de3c2571 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -15,15 +15,24 @@ from django.utils.http import http_date from django.utils.safestring import mark_safe from django.utils.translation import get_language, ugettext_lazy as _ + try: from django.urls import ( - NoReverseMatch, reverse, get_script_prefix, set_script_prefix, - Resolver404, resolve, + NoReverseMatch, + reverse, + get_script_prefix, + set_script_prefix, + Resolver404, + resolve, ) except ImportError: from django.core.urlresolvers import ( - NoReverseMatch, reverse, get_script_prefix, set_script_prefix, - Resolver404, resolve, + NoReverseMatch, + reverse, + get_script_prefix, + set_script_prefix, + Resolver404, + resolve, ) from feincms.admin.item_editor import ItemEditorForm @@ -36,9 +45,13 @@ __all__ = ( - 'ApplicationContent', - 'app_reverse', 'app_reverse_lazy', 'permalink', - 'UnpackTemplateResponse', 'standalone', 'unpack', + "ApplicationContent", + "app_reverse", + "app_reverse_lazy", + "permalink", + "UnpackTemplateResponse", + "standalone", + "unpack", ) @@ -47,6 +60,7 @@ class UnpackTemplateResponse(TemplateResponse): Completely the same as marking applicationcontent-contained views with the ``feincms.views.decorators.unpack`` decorator. """ + _feincms_unpack = True @@ -62,6 +76,7 @@ def inner(request, *args, **kwargs): if isinstance(response, HttpResponse): response.standalone = True return response + return wraps(view_func)(inner) @@ -76,19 +91,20 @@ def inner(request, *args, **kwargs): if isinstance(response, TemplateResponse): response._feincms_unpack = True return response + return wraps(view_func)(inner) def cycle_app_reverse_cache(*args, **kwargs): warnings.warn( - 'cycle_app_reverse_cache does nothing and will be removed in' - ' a future version of FeinCMS.', - DeprecationWarning, stacklevel=2, + "cycle_app_reverse_cache does nothing and will be removed in" + " a future version of FeinCMS.", + DeprecationWarning, + stacklevel=2, ) -def app_reverse(viewname, urlconf=None, args=None, kwargs=None, - *vargs, **vkwargs): +def app_reverse(viewname, urlconf=None, args=None, kwargs=None, *vargs, **vkwargs): """ Reverse URLs from application contents @@ -109,9 +125,9 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, # First parameter might be a request instead of an urlconf path, so # we'll try to be helpful and extract the current urlconf from it - extra_context = getattr(urlconf, '_feincms_extra_context', {}) - appconfig = extra_context.get('app_config', {}) - urlconf = appconfig.get('urlconf_path', urlconf) + extra_context = getattr(urlconf, "_feincms_extra_context", {}) + appconfig = extra_context.get("app_config", {}) + urlconf = appconfig.get("urlconf_path", urlconf) appcontent_class = ApplicationContent._feincms_content_models[0] cache_key = appcontent_class.app_reverse_cache_key(urlconf) @@ -124,10 +140,10 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, if urlconf in appcontent_class.ALL_APPS_CONFIG: # We have an overridden URLconf app_config = appcontent_class.ALL_APPS_CONFIG[urlconf] - urlconf = app_config['config'].get('urls', urlconf) + urlconf = app_config["config"].get("urls", urlconf) prefix = content.parent.get_absolute_url() - prefix += '/' if prefix[-1] != '/' else '' + prefix += "/" if prefix[-1] != "/" else "" url_prefix = (urlconf, prefix) cache.set(cache_key, url_prefix, timeout=APP_REVERSE_CACHE_TIMEOUT) @@ -139,11 +155,8 @@ def app_reverse(viewname, urlconf=None, args=None, kwargs=None, try: set_script_prefix(url_prefix[1]) return reverse( - viewname, - url_prefix[0], - args=args, - kwargs=kwargs, - *vargs, **vkwargs) + viewname, url_prefix[0], args=args, kwargs=kwargs, *vargs, **vkwargs + ) finally: set_script_prefix(prefix) @@ -167,8 +180,10 @@ class MyModel(models.Model): def get_absolute_url(self): return ('myapp.urls', 'model_detail', (), {'slug': self.slug}) """ + def inner(*args, **kwargs): return app_reverse(*func(*args, **kwargs)) + return wraps(func)(inner) @@ -182,8 +197,8 @@ class ApplicationContent(models.Model): class Meta: abstract = True - verbose_name = _('application content') - verbose_name_plural = _('application contents') + verbose_name = _("application content") + verbose_name_plural = _("application contents") @classmethod def initialize_type(cls, APPLICATIONS): @@ -192,7 +207,8 @@ def initialize_type(cls, APPLICATIONS): raise ValueError( "APPLICATIONS must be provided with tuples containing at" " least two parameters (urls, name) and an optional extra" - " config dict") + " config dict" + ) urls, name = i[0:2] @@ -202,20 +218,20 @@ def initialize_type(cls, APPLICATIONS): if not isinstance(app_conf, dict): raise ValueError( "The third parameter of an APPLICATIONS entry must be" - " a dict or the name of one!") + " a dict or the name of one!" + ) else: app_conf = {} - cls.ALL_APPS_CONFIG[urls] = { - "urls": urls, - "name": name, - "config": app_conf - } + cls.ALL_APPS_CONFIG[urls] = {"urls": urls, "name": name, "config": app_conf} cls.add_to_class( - 'urlconf_path', - models.CharField(_('application'), max_length=100, choices=[ - (c['urls'], c['name']) for c in cls.ALL_APPS_CONFIG.values()]) + "urlconf_path", + models.CharField( + _("application"), + max_length=100, + choices=[(c["urls"], c["name"]) for c in cls.ALL_APPS_CONFIG.values()], + ), ) class ApplicationContentItemEditorForm(ItemEditorForm): @@ -223,8 +239,7 @@ class ApplicationContentItemEditorForm(ItemEditorForm): custom_fields = {} def __init__(self, *args, **kwargs): - super(ApplicationContentItemEditorForm, self).__init__( - *args, **kwargs) + super(ApplicationContentItemEditorForm, self).__init__(*args, **kwargs) instance = kwargs.get("instance", None) @@ -233,20 +248,20 @@ def __init__(self, *args, **kwargs): # TODO use urlconf_path from POST if set # urlconf_path = request.POST.get('...urlconf_path', # instance.urlconf_path) - self.app_config = cls.ALL_APPS_CONFIG[ - instance.urlconf_path]['config'] + self.app_config = cls.ALL_APPS_CONFIG[instance.urlconf_path][ + "config" + ] except KeyError: self.app_config = {} self.custom_fields = {} - admin_fields = self.app_config.get('admin_fields', {}) + admin_fields = self.app_config.get("admin_fields", {}) if isinstance(admin_fields, dict): self.custom_fields.update(admin_fields) else: get_fields = get_object(admin_fields) - self.custom_fields.update( - get_fields(self, *args, **kwargs)) + self.custom_fields.update(get_fields(self, *args, **kwargs)) params = self.instance.parameters for k, v in self.custom_fields.items(): @@ -262,11 +277,14 @@ def save(self, commit=True, *args, **kwargs): # custom fields before calling save(commit=True) m = super(ApplicationContentItemEditorForm, self).save( - commit=False, *args, **kwargs) + commit=False, *args, **kwargs + ) m.parameters = dict( (k, self.cleaned_data[k]) - for k in self.custom_fields if k in self.cleaned_data) + for k in self.custom_fields + if k in self.cleaned_data + ) if commit: m.save(**kwargs) @@ -279,8 +297,9 @@ def save(self, commit=True, *args, **kwargs): def __init__(self, *args, **kwargs): super(ApplicationContent, self).__init__(*args, **kwargs) - self.app_config = self.ALL_APPS_CONFIG.get( - self.urlconf_path, {}).get('config', {}) + self.app_config = self.ALL_APPS_CONFIG.get(self.urlconf_path, {}).get( + "config", {} + ) def process(self, request, **kw): page_url = self.parent.get_absolute_url() @@ -290,21 +309,20 @@ def process(self, request, **kw): if "path_mapper" in self.app_config: path_mapper = get_object(self.app_config["path_mapper"]) path, page_url = path_mapper( - request.path, - page_url, - appcontent_parameters=self.parameters + request.path, page_url, appcontent_parameters=self.parameters ) else: - path = request._feincms_extra_context['extra_path'] + path = request._feincms_extra_context["extra_path"] # Resolve the module holding the application urls. - urlconf_path = self.app_config.get('urls', self.urlconf_path) + urlconf_path = self.app_config.get("urls", self.urlconf_path) try: fn, args, kwargs = resolve(path, urlconf_path) except (ValueError, Resolver404): - raise Resolver404(str('Not found (resolving %r in %r failed)') % ( - path, urlconf_path)) + raise Resolver404( + str("Not found (resolving %r in %r failed)") % (path, urlconf_path) + ) # Variables from the ApplicationContent parameters are added to request # so we can expose them to our templates via the appcontent_parameters @@ -312,19 +330,14 @@ def process(self, request, **kw): request._feincms_extra_context.update(self.parameters) # Save the application configuration for reuse elsewhere - request._feincms_extra_context.update({ - 'app_config': dict( - self.app_config, - urlconf_path=self.urlconf_path, - ), - }) + request._feincms_extra_context.update( + {"app_config": dict(self.app_config, urlconf_path=self.urlconf_path)} + ) view_wrapper = self.app_config.get("view_wrapper", None) if view_wrapper: fn = partial( - get_object(view_wrapper), - view=fn, - appcontent_parameters=self.parameters + get_object(view_wrapper), view=fn, appcontent_parameters=self.parameters ) output = fn(request, *args, **kwargs) @@ -334,33 +347,32 @@ def process(self, request, **kw): return output elif output.status_code == 200: - if self.unpack(request, output) and 'view' in kw: + if self.unpack(request, output) and "view" in kw: # Handling of @unpack and UnpackTemplateResponse - kw['view'].template_name = output.template_name - kw['view'].request._feincms_extra_context.update( - output.context_data) + kw["view"].template_name = output.template_name + kw["view"].request._feincms_extra_context.update( + output.context_data + ) else: # If the response supports deferred rendering, render the # response right now. We do not handle template response # middleware. - if hasattr(output, 'render') and callable(output.render): + if hasattr(output, "render") and callable(output.render): output.render() - self.rendered_result = mark_safe( - output.content.decode('utf-8')) + self.rendered_result = mark_safe(output.content.decode("utf-8")) self.rendered_headers = {} # Copy relevant headers for later perusal - for h in ('Cache-Control', 'Last-Modified', 'Expires'): + for h in ("Cache-Control", "Last-Modified", "Expires"): if h in output: - self.rendered_headers.setdefault( - h, []).append(output[h]) + self.rendered_headers.setdefault(h, []).append(output[h]) - elif isinstance(output, tuple) and 'view' in kw: - kw['view'].template_name = output[0] - kw['view'].request._feincms_extra_context.update(output[1]) + elif isinstance(output, tuple) and "view" in kw: + kw["view"].template_name = output[0] + kw["view"].request._feincms_extra_context.update(output[1]) else: self.rendered_result = mark_safe(output) @@ -368,25 +380,26 @@ def process(self, request, **kw): return True # successful def send_directly(self, request, response): - mimetype = response.get('Content-Type', 'text/plain') - if ';' in mimetype: - mimetype = mimetype.split(';')[0] + mimetype = response.get("Content-Type", "text/plain") + if ";" in mimetype: + mimetype = mimetype.split(";")[0] mimetype = mimetype.strip() return ( - response.status_code != 200 or - request.is_ajax() or - getattr(response, 'standalone', False) or - mimetype not in ('text/html', 'text/plain')) + response.status_code != 200 + or request.is_ajax() + or getattr(response, "standalone", False) + or mimetype not in ("text/html", "text/plain") + ) def unpack(self, request, response): - return getattr(response, '_feincms_unpack', False) + return getattr(response, "_feincms_unpack", False) def render(self, **kwargs): - return getattr(self, 'rendered_result', '') + return getattr(self, "rendered_result", "") def finalize(self, request, response): - headers = getattr(self, 'rendered_headers', None) + headers = getattr(self, "rendered_headers", None) if headers: self._update_response_headers(request, response, headers) @@ -399,29 +412,29 @@ def _update_response_headers(self, request, response, headers): # Ideally, for the Cache-Control header, we'd want to do some # intelligent combining, but that's hard. Let's just collect and unique # them and let the client worry about that. - cc_headers = set(('must-revalidate',)) - for x in (cc.split(",") for cc in headers.get('Cache-Control', ())): + cc_headers = set(("must-revalidate",)) + for x in (cc.split(",") for cc in headers.get("Cache-Control", ())): cc_headers |= set((s.strip() for s in x)) if len(cc_headers): - response['Cache-Control'] = ", ".join(cc_headers) - else: # Default value - response['Cache-Control'] = 'no-cache, must-revalidate' + response["Cache-Control"] = ", ".join(cc_headers) + else: # Default value + response["Cache-Control"] = "no-cache, must-revalidate" # Check all Last-Modified headers, choose the latest one - lm_list = [parsedate(x) for x in headers.get('Last-Modified', ())] + lm_list = [parsedate(x) for x in headers.get("Last-Modified", ())] if len(lm_list) > 0: - response['Last-Modified'] = http_date(mktime(max(lm_list))) + response["Last-Modified"] = http_date(mktime(max(lm_list))) # Check all Expires headers, choose the earliest one - lm_list = [parsedate(x) for x in headers.get('Expires', ())] + lm_list = [parsedate(x) for x in headers.get("Expires", ())] if len(lm_list) > 0: - response['Expires'] = http_date(mktime(min(lm_list))) + response["Expires"] = http_date(mktime(min(lm_list))) @classmethod def app_reverse_cache_key(self, urlconf_path, **kwargs): - return 'FEINCMS:%s:APPCONTENT:%s:%s' % ( - getattr(settings, 'SITE_ID', 0), + return "FEINCMS:%s:APPCONTENT:%s:%s" % ( + getattr(settings, "SITE_ID", 0), get_language(), urlconf_path, ) @@ -433,17 +446,21 @@ def closest_match(cls, urlconf_path): except AttributeError: page_class = cls.parent.field.rel.to - contents = cls.objects.filter( - parent__in=page_class.objects.active(), - urlconf_path=urlconf_path, - ).order_by('pk').select_related('parent') + contents = ( + cls.objects.filter( + parent__in=page_class.objects.active(), urlconf_path=urlconf_path + ) + .order_by("pk") + .select_related("parent") + ) if len(contents) > 1: try: current = short_language_code(get_language()) return [ - content for content in contents if - short_language_code(content.parent.language) == current + content + for content in contents + if short_language_code(content.parent.language) == current ][0] except (AttributeError, IndexError): diff --git a/feincms/content/contactform/__init__.py b/feincms/content/contactform/__init__.py index f76f4292e..c25396137 100644 --- a/feincms/content/contactform/__init__.py +++ b/feincms/content/contactform/__init__.py @@ -4,5 +4,7 @@ import warnings warnings.warn( - 'The contactform content has been deprecated. Use form-designer instead.', - DeprecationWarning, stacklevel=2) + "The contactform content has been deprecated. Use form-designer instead.", + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index cfda97377..9bf97a793 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -18,13 +18,11 @@ class ContactForm(forms.Form): - name = forms.CharField(label=_('name')) - email = forms.EmailField(label=_('email')) - subject = forms.CharField(label=_('subject')) + name = forms.CharField(label=_("name")) + email = forms.EmailField(label=_("email")) + subject = forms.CharField(label=_("subject")) - content = forms.CharField( - widget=forms.Textarea, required=False, - label=_('content')) + content = forms.CharField(widget=forms.Textarea, required=False, label=_("content")) class ContactFormContent(models.Model): @@ -35,8 +33,8 @@ class ContactFormContent(models.Model): class Meta: abstract = True - verbose_name = _('contact form') - verbose_name_plural = _('contact forms') + verbose_name = _("contact form") + verbose_name_plural = _("contact forms") @classmethod def initialize_type(cls, form=None): @@ -44,42 +42,40 @@ def initialize_type(cls, form=None): cls.form = form def process(self, request, **kwargs): - if request.GET.get('_cf_thanks'): + if request.GET.get("_cf_thanks"): self.rendered_output = ct_render_to_string( - 'content/contactform/thanks.html', - {'content': self}, - request=request) + "content/contactform/thanks.html", {"content": self}, request=request + ) return - if request.method == 'POST': + if request.method == "POST": form = self.form(request.POST) if form.is_valid(): send_mail( - form.cleaned_data['subject'], - render_to_string('content/contactform/email.txt', { - 'data': form.cleaned_data, - }), - form.cleaned_data['email'], + form.cleaned_data["subject"], + render_to_string( + "content/contactform/email.txt", {"data": form.cleaned_data} + ), + form.cleaned_data["email"], [self.email], fail_silently=True, ) - return HttpResponseRedirect('?_cf_thanks=1') + return HttpResponseRedirect("?_cf_thanks=1") else: - initial = {'subject': self.subject} + initial = {"subject": self.subject} if request.user.is_authenticated(): - initial['email'] = request.user.email - initial['name'] = request.user.get_full_name() + initial["email"] = request.user.email + initial["name"] = request.user.get_full_name() form = self.form(initial=initial) self.rendered_output = ct_render_to_string( - 'content/contactform/form.html', { - 'content': self, - 'form': form, - }, - request=request) + "content/contactform/form.html", + {"content": self, "form": form}, + request=request, + ) def render(self, **kwargs): - return getattr(self, 'rendered_output', '') + return getattr(self, "rendered_output", "") diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index fda078a9f..acfab79ec 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -20,21 +20,20 @@ class FileContent(models.Model): title = models.CharField(max_length=200) file = models.FileField( - _('file'), max_length=255, - upload_to=os.path.join(settings.FEINCMS_UPLOAD_PREFIX, 'filecontent')) + _("file"), + max_length=255, + upload_to=os.path.join(settings.FEINCMS_UPLOAD_PREFIX, "filecontent"), + ) class Meta: abstract = True - verbose_name = _('file') - verbose_name_plural = _('files') + verbose_name = _("file") + verbose_name_plural = _("files") def render(self, **kwargs): return ct_render_to_string( - [ - 'content/file/%s.html' % self.region, - 'content/file/default.html', - ], - {'content': self}, - request=kwargs.get('request'), - context=kwargs.get('context'), + ["content/file/%s.html" % self.region, "content/file/default.html"], + {"content": self}, + request=kwargs.get("request"), + context=kwargs.get("context"), ) diff --git a/feincms/content/filer/models.py b/feincms/content/filer/models.py index f728f0fa1..351b3e628 100644 --- a/feincms/content/filer/models.py +++ b/feincms/content/filer/models.py @@ -17,17 +17,20 @@ else: __all__ = ( - 'MediaFileContentInline', 'ContentWithFilerFile', - 'FilerFileContent', 'FilerImageContent', + "MediaFileContentInline", + "ContentWithFilerFile", + "FilerFileContent", + "FilerImageContent", ) class MediaFileContentInline(FeinCMSInline): - radio_fields = {'type': admin.VERTICAL} + radio_fields = {"type": admin.VERTICAL} class ContentWithFilerFile(models.Model): """ File content """ + feincms_item_editor_inline = MediaFileContentInline class Meta: @@ -36,25 +39,25 @@ class Meta: def render(self, **kwargs): return ct_render_to_string( [ - 'content/filer/%s_%s.html' % (self.file_type, self.type), - 'content/filer/%s.html' % self.type, - 'content/filer/%s.html' % self.file_type, - 'content/filer/default.html', + "content/filer/%s_%s.html" % (self.file_type, self.type), + "content/filer/%s.html" % self.type, + "content/filer/%s.html" % self.file_type, + "content/filer/default.html", ], - {'content': self}, - request=kwargs.get('request'), - context=kwargs.get('context'), + {"content": self}, + request=kwargs.get("request"), + context=kwargs.get("context"), ) class FilerFileContent(ContentWithFilerFile): - mediafile = FilerFileField(verbose_name=_('file'), related_name='+') - file_type = 'file' - type = 'download' + mediafile = FilerFileField(verbose_name=_("file"), related_name="+") + file_type = "file" + type = "download" class Meta: abstract = True - verbose_name = _('file') - verbose_name_plural = _('files') + verbose_name = _("file") + verbose_name_plural = _("files") class FilerImageContent(ContentWithFilerFile): """ @@ -83,36 +86,28 @@ class FilerImageContent(ContentWithFilerFile): must_always_publish_copyright, date_taken, file, id, is_public, url """ - mediafile = FilerImageField(verbose_name=_('image'), related_name='+') - caption = models.CharField( - _('caption'), - max_length=1000, - blank=True, - ) - url = models.CharField( - _('URL'), - max_length=1000, - blank=True, - ) + mediafile = FilerImageField(verbose_name=_("image"), related_name="+") + caption = models.CharField(_("caption"), max_length=1000, blank=True) + url = models.CharField(_("URL"), max_length=1000, blank=True) - file_type = 'image' + file_type = "image" class Meta: abstract = True - verbose_name = _('image') - verbose_name_plural = _('images') + verbose_name = _("image") + verbose_name_plural = _("images") @classmethod def initialize_type(cls, TYPE_CHOICES=None): if TYPE_CHOICES is None: raise ImproperlyConfigured( - 'You have to set TYPE_CHOICES when' - ' creating a %s' % cls.__name__) + "You have to set TYPE_CHOICES when" " creating a %s" % cls.__name__ + ) cls.add_to_class( - 'type', + "type", models.CharField( - _('type'), + _("type"), max_length=20, choices=TYPE_CHOICES, default=TYPE_CHOICES[0][0], diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index 170236a92..8ddec6c37 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -43,54 +43,59 @@ class ImageContent(models.Model): """ image = models.ImageField( - _('image'), max_length=255, - upload_to=os.path.join(settings.FEINCMS_UPLOAD_PREFIX, 'imagecontent')) + _("image"), + max_length=255, + upload_to=os.path.join(settings.FEINCMS_UPLOAD_PREFIX, "imagecontent"), + ) alt_text = models.CharField( - _('alternate text'), max_length=255, blank=True, - help_text=_('Description of image')) - caption = models.CharField(_('caption'), max_length=255, blank=True) + _("alternate text"), + max_length=255, + blank=True, + help_text=_("Description of image"), + ) + caption = models.CharField(_("caption"), max_length=255, blank=True) class Meta: abstract = True - verbose_name = _('image') - verbose_name_plural = _('images') + verbose_name = _("image") + verbose_name_plural = _("images") def render(self, **kwargs): - templates = ['content/image/default.html'] - if hasattr(self, 'position'): - templates.insert(0, 'content/image/%s.html' % self.position) + templates = ["content/image/default.html"] + if hasattr(self, "position"): + templates.insert(0, "content/image/%s.html" % self.position) return ct_render_to_string( templates, - {'content': self}, - request=kwargs.get('request'), - context=kwargs.get('context'), + {"content": self}, + request=kwargs.get("request"), + context=kwargs.get("context"), ) def get_image(self): - type, separator, size = getattr(self, 'format', '').partition(':') + type, separator, size = getattr(self, "format", "").partition(":") if not size: return self.image - thumbnailer = { - 'cropscale': feincms_thumbnail.CropscaleThumbnailer, - }.get(type, feincms_thumbnail.Thumbnailer) + thumbnailer = {"cropscale": feincms_thumbnail.CropscaleThumbnailer}.get( + type, feincms_thumbnail.Thumbnailer + ) return thumbnailer(self.image, size) @classmethod def initialize_type(cls, POSITION_CHOICES=None, FORMAT_CHOICES=None): if POSITION_CHOICES: models.CharField( - _('position'), + _("position"), max_length=10, choices=POSITION_CHOICES, - default=POSITION_CHOICES[0][0] - ).contribute_to_class(cls, 'position') + default=POSITION_CHOICES[0][0], + ).contribute_to_class(cls, "position") if FORMAT_CHOICES: models.CharField( - _('format'), + _("format"), max_length=64, choices=FORMAT_CHOICES, - default=FORMAT_CHOICES[0][0] - ).contribute_to_class(cls, 'format') + default=FORMAT_CHOICES[0][0], + ).contribute_to_class(cls, "format") diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index 9e8d2e30d..bc7d2f474 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -6,5 +6,7 @@ from feincms.module.medialibrary.contents import MediaFileContent warnings.warn( - 'Import MediaFileContent from feincms.module.medialibrary.contents.', - DeprecationWarning, stacklevel=2) + "Import MediaFileContent from feincms.module.medialibrary.contents.", + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/content/raw/models.py b/feincms/content/raw/models.py index 487c5a241..283d6c151 100644 --- a/feincms/content/raw/models.py +++ b/feincms/content/raw/models.py @@ -13,12 +13,12 @@ class RawContent(models.Model): snippets too. """ - text = models.TextField(_('content'), blank=True) + text = models.TextField(_("content"), blank=True) class Meta: abstract = True - verbose_name = _('raw content') - verbose_name_plural = _('raw contents') + verbose_name = _("raw content") + verbose_name_plural = _("raw contents") def render(self, **kwargs): return mark_safe(self.text) diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index 8ad5a1e9c..a893eb1b4 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -24,26 +24,21 @@ class RichTextContent(models.Model): feincms_item_editor_context_processors = ( lambda x: settings.FEINCMS_RICHTEXT_INIT_CONTEXT, ) - feincms_item_editor_includes = { - 'head': [settings.FEINCMS_RICHTEXT_INIT_TEMPLATE], - } + feincms_item_editor_includes = {"head": [settings.FEINCMS_RICHTEXT_INIT_TEMPLATE]} class Meta: abstract = True - verbose_name = _('rich text') - verbose_name_plural = _('rich texts') + verbose_name = _("rich text") + verbose_name_plural = _("rich texts") def render(self, **kwargs): return ct_render_to_string( - 'content/richtext/default.html', - {'content': self}, - request=kwargs.get('request'), - context=kwargs.get('context'), + "content/richtext/default.html", + {"content": self}, + request=kwargs.get("request"), + context=kwargs.get("context"), ) @classmethod def initialize_type(cls, cleanse=None): - cls.add_to_class( - 'text', - RichTextField(_('text'), blank=True, cleanse=cleanse), - ) + cls.add_to_class("text", RichTextField(_("text"), blank=True, cleanse=cleanse)) diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 44dbdf571..4af9a8b3a 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -15,8 +15,8 @@ class SectionContentInline(FeinCMSInline): - raw_id_fields = ('mediafile',) - radio_fields = {'type': admin.VERTICAL} + raw_id_fields = ("mediafile",) + radio_fields = {"type": admin.VERTICAL} class SectionContent(models.Model): @@ -28,39 +28,46 @@ class SectionContent(models.Model): feincms_item_editor_context_processors = ( lambda x: settings.FEINCMS_RICHTEXT_INIT_CONTEXT, ) - feincms_item_editor_includes = { - 'head': [settings.FEINCMS_RICHTEXT_INIT_TEMPLATE], - } + feincms_item_editor_includes = {"head": [settings.FEINCMS_RICHTEXT_INIT_TEMPLATE]} - title = models.CharField(_('title'), max_length=200, blank=True) - richtext = RichTextField(_('text'), blank=True) + title = models.CharField(_("title"), max_length=200, blank=True) + richtext = RichTextField(_("text"), blank=True) mediafile = MediaFileForeignKey( - MediaFile, on_delete=models.CASCADE, - verbose_name=_('media file'), - related_name='+', blank=True, null=True) + MediaFile, + on_delete=models.CASCADE, + verbose_name=_("media file"), + related_name="+", + blank=True, + null=True, + ) class Meta: abstract = True - verbose_name = _('section') - verbose_name_plural = _('sections') + verbose_name = _("section") + verbose_name_plural = _("sections") @classmethod def initialize_type(cls, TYPE_CHOICES=None, cleanse=None): - if 'feincms.module.medialibrary' not in django_settings.INSTALLED_APPS: + if "feincms.module.medialibrary" not in django_settings.INSTALLED_APPS: raise ImproperlyConfigured( - 'You have to add \'feincms.module.medialibrary\' to your' - ' INSTALLED_APPS before creating a %s' % cls.__name__) + "You have to add 'feincms.module.medialibrary' to your" + " INSTALLED_APPS before creating a %s" % cls.__name__ + ) if TYPE_CHOICES is None: raise ImproperlyConfigured( - 'You need to set TYPE_CHOICES when creating a' - ' %s' % cls.__name__) - - cls.add_to_class('type', models.CharField( - _('type'), - max_length=10, choices=TYPE_CHOICES, - default=TYPE_CHOICES[0][0] - )) + "You need to set TYPE_CHOICES when creating a" " %s" % cls.__name__ + ) + + cls.add_to_class( + "type", + models.CharField( + _("type"), + max_length=10, + choices=TYPE_CHOICES, + default=TYPE_CHOICES[0][0], + ), + ) if cleanse: cls.cleanse = cleanse @@ -68,29 +75,28 @@ def initialize_type(cls, TYPE_CHOICES=None, cleanse=None): @classmethod def get_queryset(cls, filter_args): # Explicitly add nullable FK mediafile to minimize the DB query count - return cls.objects.select_related('parent', 'mediafile').filter( - filter_args) + return cls.objects.select_related("parent", "mediafile").filter(filter_args) def render(self, **kwargs): if self.mediafile: mediafile_type = self.mediafile.type else: - mediafile_type = 'nomedia' + mediafile_type = "nomedia" return ct_render_to_string( [ - 'content/section/%s_%s.html' % (mediafile_type, self.type), - 'content/section/%s.html' % mediafile_type, - 'content/section/%s.html' % self.type, - 'content/section/default.html', + "content/section/%s_%s.html" % (mediafile_type, self.type), + "content/section/%s.html" % mediafile_type, + "content/section/%s.html" % self.type, + "content/section/default.html", ], - {'content': self}, - request=kwargs.get('request'), - context=kwargs.get('context'), + {"content": self}, + request=kwargs.get("request"), + context=kwargs.get("context"), ) def save(self, *args, **kwargs): - if getattr(self, 'cleanse', None): + if getattr(self, "cleanse", None): try: # Passes the rich text content as first argument because # the passed callable has been converted into a bound method @@ -101,4 +107,5 @@ def save(self, *args, **kwargs): self.richtext = self.cleanse.im_func(self.richtext) super(SectionContent, self).save(*args, **kwargs) + save.alters_data = True diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 26ec26e44..ad203b3d9 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -19,23 +19,23 @@ class TemplateContent(models.Model): ('base.html', 'makes no sense'), ]) """ + class Meta: abstract = True - verbose_name = _('template content') - verbose_name_plural = _('template contents') + verbose_name = _("template content") + verbose_name_plural = _("template contents") @classmethod def initialize_type(cls, TEMPLATES): - cls.add_to_class('template', models.CharField( - _('template'), - max_length=100, - choices=TEMPLATES, - )) + cls.add_to_class( + "template", + models.CharField(_("template"), max_length=100, choices=TEMPLATES), + ) def render(self, **kwargs): return ct_render_to_string( self.template, - {'content': self}, - request=kwargs.get('request'), - context=kwargs.get('context'), + {"content": self}, + request=kwargs.get("request"), + context=kwargs.get("context"), ) diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index 32a4cae81..1e73cf83a 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -20,38 +20,43 @@ class VideoContent(models.Model): """ PORTALS = ( - ('youtube', re.compile(r'youtube'), lambda url: { - 'v': re.search(r'([?&]v=|./././)([^#&]+)', url).group(2), - }), - ('vimeo', re.compile(r'vimeo'), lambda url: { - 'id': re.search(r'/(\d+)', url).group(1), - }), - ('sf', re.compile(r'sf\.tv'), lambda url: { - 'id': re.search(r'/([a-z0-9\-]+)', url).group(1), - }), + ( + "youtube", + re.compile(r"youtube"), + lambda url: {"v": re.search(r"([?&]v=|./././)([^#&]+)", url).group(2)}, + ), + ( + "vimeo", + re.compile(r"vimeo"), + lambda url: {"id": re.search(r"/(\d+)", url).group(1)}, + ), + ( + "sf", + re.compile(r"sf\.tv"), + lambda url: {"id": re.search(r"/([a-z0-9\-]+)", url).group(1)}, + ), ) video = models.URLField( - _('video link'), + _("video link"), help_text=_( - 'This should be a link to a youtube or vimeo video,' - ' i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0')) + "This should be a link to a youtube or vimeo video," + " i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0" + ), + ) class Meta: abstract = True - verbose_name = _('video') - verbose_name_plural = _('videos') + verbose_name = _("video") + verbose_name_plural = _("videos") def get_context_dict(self): "Extend this if you need more variables passed to template" - return {'content': self, 'portal': 'unknown'} + return {"content": self, "portal": "unknown"} - def get_templates(self, portal='unknown'): + def get_templates(self, portal="unknown"): "Extend/override this if you want to modify the templates used" - return [ - 'content/video/%s.html' % portal, - 'content/video/unknown.html', - ] + return ["content/video/%s.html" % portal, "content/video/unknown.html"] def ctx_for_video(self, vurl): "Get a context dict for a given video URL" @@ -60,7 +65,7 @@ def ctx_for_video(self, vurl): if match.search(vurl): try: ctx.update(context_fn(vurl)) - ctx['portal'] = portal + ctx["portal"] = portal break except AttributeError: continue @@ -69,8 +74,8 @@ def ctx_for_video(self, vurl): def render(self, **kwargs): ctx = self.ctx_for_video(self.video) return ct_render_to_string( - self.get_templates(ctx['portal']), + self.get_templates(ctx["portal"]), ctx, - request=kwargs.get('request'), - context=kwargs.get('context'), + request=kwargs.get("request"), + context=kwargs.get("context"), ) diff --git a/feincms/context_processors.py b/feincms/context_processors.py index 3f5c9b1a7..30bf7de70 100644 --- a/feincms/context_processors.py +++ b/feincms/context_processors.py @@ -7,8 +7,6 @@ def add_page_if_missing(request): """ try: - return { - 'feincms_page': Page.objects.for_request(request, best_match=True), - } + return {"feincms_page": Page.objects.for_request(request, best_match=True)} except Page.DoesNotExist: return {} diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 37af3bdec..bf8b8ed3b 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -32,11 +32,10 @@ def clean(self, value, *args, **kwargs): return super(JSONFormField, self).clean(value, *args, **kwargs) -if LooseVersion(get_version()) > LooseVersion('1.8'): +if LooseVersion(get_version()) > LooseVersion("1.8"): workaround_class = models.TextField else: - workaround_class = six.with_metaclass( - models.SubfieldBase, models.TextField) + workaround_class = six.with_metaclass(models.SubfieldBase, models.TextField) class JSONField(workaround_class): @@ -54,8 +53,7 @@ def to_python(self, value): if isinstance(value, dict): return value - elif (isinstance(value, six.string_types) or - isinstance(value, six.binary_type)): + elif isinstance(value, six.string_types) or isinstance(value, six.binary_type): # Avoid asking the JSON decoder to handle empty values: if not value: return {} @@ -64,7 +62,8 @@ def to_python(self, value): return json.loads(value) except ValueError: logging.getLogger("feincms.contrib.fields").exception( - "Unable to deserialize store JSONField data: %s", value) + "Unable to deserialize store JSONField data: %s", value + ) return {} else: assert value is None diff --git a/feincms/contrib/preview/urls.py b/feincms/contrib/preview/urls.py index 1f4e324f0..95facb066 100644 --- a/feincms/contrib/preview/urls.py +++ b/feincms/contrib/preview/urls.py @@ -4,6 +4,5 @@ urlpatterns = [ - url(r'^(.*)/_preview/(\d+)/$', PreviewHandler.as_view(), - name='feincms_preview'), + url(r"^(.*)/_preview/(\d+)/$", PreviewHandler.as_view(), name="feincms_preview") ] diff --git a/feincms/contrib/preview/views.py b/feincms/contrib/preview/views.py index e1c37586c..38ba1d6d1 100644 --- a/feincms/contrib/preview/views.py +++ b/feincms/contrib/preview/views.py @@ -29,9 +29,7 @@ def get_object(self): def handler(self, request, *args, **kwargs): if not request.user.is_staff: - raise Http404('Not found (not allowed)') - response = super(PreviewHandler, self).handler( - request, *args, **kwargs) - response['Cache-Control'] =\ - 'no-cache, must-revalidate, no-store, private' + raise Http404("Not found (not allowed)") + response = super(PreviewHandler, self).handler(request, *args, **kwargs) + response["Cache-Control"] = "no-cache, must-revalidate, no-store, private" return response diff --git a/feincms/contrib/richtext.py b/feincms/contrib/richtext.py index 3b9985e55..4e027ea80 100644 --- a/feincms/contrib/richtext.py +++ b/feincms/contrib/richtext.py @@ -6,11 +6,11 @@ class RichTextFormField(forms.fields.CharField): def __init__(self, *args, **kwargs): - self.cleanse = kwargs.pop('cleanse', None) + self.cleanse = kwargs.pop("cleanse", None) super(RichTextFormField, self).__init__(*args, **kwargs) - css_class = self.widget.attrs.get('class', '') - css_class += ' item-richtext' - self.widget.attrs['class'] = css_class + css_class = self.widget.attrs.get("class", "") + css_class += " item-richtext" + self.widget.attrs["class"] = css_class def clean(self, value): value = super(RichTextFormField, self).clean(value) @@ -24,12 +24,12 @@ class RichTextField(models.TextField): Drop-in replacement for Django's ``models.TextField`` which allows editing rich text instead of plain text in the item editor. """ + def __init__(self, *args, **kwargs): - self.cleanse = kwargs.pop('cleanse', None) + self.cleanse = kwargs.pop("cleanse", None) super(RichTextField, self).__init__(*args, **kwargs) def formfield(self, form_class=RichTextFormField, **kwargs): return super(RichTextField, self).formfield( - form_class=form_class, - cleanse=self.cleanse, - **kwargs) + form_class=form_class, cleanse=self.cleanse, **kwargs + ) diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 6520f069c..181f4eed9 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -19,6 +19,7 @@ from tagging.fields import TagField from tagging.models import Tag from tagging.utils import parse_tag_input + try: from tagging.registry import AlreadyRegistered except ImportError: @@ -27,12 +28,13 @@ # ------------------------------------------------------------------------ def taglist_to_string(taglist): - retval = '' + retval = "" if len(taglist) >= 1: taglist.sort() - retval = ','.join(taglist) + retval = ",".join(taglist) return retval + # ------------------------------------------------------------------------ # The following is lifted from: # http://code.google.com/p/django-tagging/issues/detail?id=189 @@ -57,19 +59,23 @@ def clean(self, value): if VERSION >= (1, 10): + class Tag_formatvalue_mixin(object): def format_value(self, value): - value = parse_tag_input(value or '') + value = parse_tag_input(value or "") return super(Tag_formatvalue_mixin, self).format_value(value) + + else: # _format_value is a private method previous to Django 1.10, # do the job in render() instead to avoid fiddling with # anybody's privates class Tag_formatvalue_mixin(object): def render(self, name, value, attrs=None, *args, **kwargs): - value = parse_tag_input(value or '') + value = parse_tag_input(value or "") return super(Tag_formatvalue_mixin, self).render( - name, value, attrs, *args, **kwargs) + name, value, attrs, *args, **kwargs + ) class fv_FilteredSelectMultiple(Tag_formatvalue_mixin, FilteredSelectMultiple): @@ -87,17 +93,13 @@ def __init__(self, filter_horizontal=False, *args, **kwargs): def formfield(self, **defaults): if self.filter_horizontal: - widget = fv_FilteredSelectMultiple( - self.verbose_name, is_stacked=False) + widget = fv_FilteredSelectMultiple(self.verbose_name, is_stacked=False) else: widget = fv_SelectMultiple() - defaults['widget'] = widget - choices = [( - six.text_type(t), - six.text_type(t)) for t in Tag.objects.all()] - return TagSelectFormField( - choices=choices, required=not self.blank, **defaults) + defaults["widget"] = widget + choices = [(six.text_type(t), six.text_type(t)) for t in Tag.objects.all()] + return TagSelectFormField(choices=choices, required=not self.blank, **defaults) # ------------------------------------------------------------------------ @@ -111,9 +113,15 @@ def pre_save_handler(sender, instance, **kwargs): # ------------------------------------------------------------------------ -def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, - select_field=False, auto_add_admin_field=True, - admin_list_display=True): +def tag_model( + cls, + admin_cls=None, + field_name="tags", + sort_tags=False, + select_field=False, + auto_add_admin_field=True, + admin_list_display=True, +): """ tag_model accepts a number of named parameters: @@ -136,14 +144,17 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, except ImportError: from tagging import register as tagging_register - cls.add_to_class(field_name, ( - TagSelectField if select_field else TagField - )(field_name.capitalize(), blank=True)) + cls.add_to_class( + field_name, + (TagSelectField if select_field else TagField)( + field_name.capitalize(), blank=True + ), + ) # use another name for the tag descriptor # See http://code.google.com/p/django-tagging/issues/detail?id=95 for the # reason why try: - tagging_register(cls, tag_descriptor_attr='tagging_' + field_name) + tagging_register(cls, tag_descriptor_attr="tagging_" + field_name) except AlreadyRegistered: return @@ -152,13 +163,11 @@ def tag_model(cls, admin_cls=None, field_name='tags', sort_tags=False, admin_cls.list_display.append(field_name) admin_cls.list_filter.append(field_name) - if auto_add_admin_field and hasattr( - admin_cls, 'add_extension_options'): - admin_cls.add_extension_options(_('Tagging'), { - 'fields': (field_name,) - }) + if auto_add_admin_field and hasattr(admin_cls, "add_extension_options"): + admin_cls.add_extension_options(_("Tagging"), {"fields": (field_name,)}) if sort_tags: pre_save.connect(pre_save_handler, sender=cls) + # ------------------------------------------------------------------------ diff --git a/feincms/default_settings.py b/feincms/default_settings.py index 3cbf95f2c..53c4a41ef 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -14,42 +14,41 @@ # e.g. 'uploads' if you would prefer /uploads/imagecontent/test.jpg # to /imagecontent/test.jpg. -FEINCMS_UPLOAD_PREFIX = getattr( - settings, - 'FEINCMS_UPLOAD_PREFIX', - '') +FEINCMS_UPLOAD_PREFIX = getattr(settings, "FEINCMS_UPLOAD_PREFIX", "") # ------------------------------------------------------------------------ # Settings for MediaLibrary #: Local path to newly uploaded media files FEINCMS_MEDIALIBRARY_UPLOAD_TO = getattr( - settings, - 'FEINCMS_MEDIALIBRARY_UPLOAD_TO', - 'medialibrary/%Y/%m/') + settings, "FEINCMS_MEDIALIBRARY_UPLOAD_TO", "medialibrary/%Y/%m/" +) #: Thumbnail function for suitable mediafiles. Only receives the media file #: and should return a thumbnail URL (or nothing). FEINCMS_MEDIALIBRARY_THUMBNAIL = getattr( settings, - 'FEINCMS_MEDIALIBRARY_THUMBNAIL', - 'feincms.module.medialibrary.thumbnail.default_admin_thumbnail') + "FEINCMS_MEDIALIBRARY_THUMBNAIL", + "feincms.module.medialibrary.thumbnail.default_admin_thumbnail", +) # ------------------------------------------------------------------------ # Settings for RichText FEINCMS_RICHTEXT_INIT_TEMPLATE = getattr( settings, - 'FEINCMS_RICHTEXT_INIT_TEMPLATE', - 'admin/content/richtext/init_tinymce4.html') + "FEINCMS_RICHTEXT_INIT_TEMPLATE", + "admin/content/richtext/init_tinymce4.html", +) FEINCMS_RICHTEXT_INIT_CONTEXT = getattr( settings, - 'FEINCMS_RICHTEXT_INIT_CONTEXT', { - 'TINYMCE_JS_URL': '//tinymce.cachefly.net/4.2/tinymce.min.js', - 'TINYMCE_DOMAIN': None, - 'TINYMCE_CONTENT_CSS_URL': None, - 'TINYMCE_LINK_LIST_URL': None - } + "FEINCMS_RICHTEXT_INIT_CONTEXT", + { + "TINYMCE_JS_URL": "//tinymce.cachefly.net/4.2/tinymce.min.js", + "TINYMCE_DOMAIN": None, + "TINYMCE_CONTENT_CSS_URL": None, + "TINYMCE_LINK_LIST_URL": None, + }, ) # ------------------------------------------------------------------------ @@ -57,38 +56,29 @@ #: Include ancestors in filtered tree editor lists FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS = getattr( - settings, - 'FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS', - False) + settings, "FEINCMS_TREE_EDITOR_INCLUDE_ANCESTORS", False +) #: Enable checking of object level permissions. Note that if this option is #: enabled, you must plug in an authentication backend that actually does #: implement object level permissions or no page will be editable. FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS = getattr( - settings, - 'FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS', - False) + settings, "FEINCMS_TREE_EDITOR_OBJECT_PERMISSIONS", False +) #: When enabled, the page module is automatically registered with Django's #: default admin site (this is activated by default). -FEINCMS_USE_PAGE_ADMIN = getattr( - settings, - 'FEINCMS_USE_PAGE_ADMIN', - True) +FEINCMS_USE_PAGE_ADMIN = getattr(settings, "FEINCMS_USE_PAGE_ADMIN", True) #: app_label.model_name as per apps.get_model. #: defaults to page.Page FEINCMS_DEFAULT_PAGE_MODEL = getattr( - settings, - 'FEINCMS_DEFAULT_PAGE_MODEL', - 'page.Page') + settings, "FEINCMS_DEFAULT_PAGE_MODEL", "page.Page" +) # ------------------------------------------------------------------------ #: Allow random gunk after a valid page? -FEINCMS_ALLOW_EXTRA_PATH = getattr( - settings, - 'FEINCMS_ALLOW_EXTRA_PATH', - False) +FEINCMS_ALLOW_EXTRA_PATH = getattr(settings, "FEINCMS_ALLOW_EXTRA_PATH", False) # ------------------------------------------------------------------------ #: How to switch languages. @@ -96,10 +86,7 @@ #: and overwrites whatever was set before. #: * ``'EXPLICIT'``: The language set has priority, may only be overridden #: by explicitely a language with ``?set_language=xx``. -FEINCMS_TRANSLATION_POLICY = getattr( - settings, - 'FEINCMS_TRANSLATION_POLICY', - 'STANDARD') +FEINCMS_TRANSLATION_POLICY = getattr(settings, "FEINCMS_TRANSLATION_POLICY", "STANDARD") # ------------------------------------------------------------------------ #: Makes the page handling mechanism try to find a cms page with that @@ -107,60 +94,45 @@ #: customised cms-styled error pages. Do not go overboard, this should #: be as simple and as error resistant as possible, so refrain from #: deeply nested error pages or advanced content types. -FEINCMS_CMS_404_PAGE = getattr( - settings, - 'FEINCMS_CMS_404_PAGE', - None) +FEINCMS_CMS_404_PAGE = getattr(settings, "FEINCMS_CMS_404_PAGE", None) # ------------------------------------------------------------------------ #: When uploading files to the media library, replacing an existing entry, #: try to save the new file under the old file name in order to keep the #: media file path (and thus the media url) constant. #: Experimental, this might not work with all storage backends. -FEINCMS_MEDIAFILE_OVERWRITE = getattr( - settings, - 'FEINCMS_MEDIAFILE_OVERWRITE', - False) +FEINCMS_MEDIAFILE_OVERWRITE = getattr(settings, "FEINCMS_MEDIAFILE_OVERWRITE", False) # ------------------------------------------------------------------------ #: Prefix for thumbnails. Set this to something non-empty to separate thumbs #: from uploads. The value should end with a slash, but this is not enforced. -FEINCMS_THUMBNAIL_DIR = getattr( - settings, - 'FEINCMS_THUMBNAIL_DIR', - '_thumbs/') +FEINCMS_THUMBNAIL_DIR = getattr(settings, "FEINCMS_THUMBNAIL_DIR", "_thumbs/") # ------------------------------------------------------------------------ #: feincms_thumbnail template filter library cache timeout. The default is to #: not cache anything for backwards compatibility. FEINCMS_THUMBNAIL_CACHE_TIMEOUT = getattr( - settings, - 'FEINCMS_THUMBNAIL_CACHE_TIMEOUT', - 0) + settings, "FEINCMS_THUMBNAIL_CACHE_TIMEOUT", 0 +) # ------------------------------------------------------------------------ #: Prevent changing template within admin for pages which have been #: allocated a Template with singleton=True -- template field will become #: read-only for singleton pages. FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED = getattr( - settings, - 'FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED', - False) + settings, "FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED", False +) #: Prevent admin page deletion for pages which have been allocated a #: Template with singleton=True FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED = getattr( - settings, - 'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED', - False) + settings, "FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED", False +) # ------------------------------------------------------------------------ #: Filter languages available for front end users to this set. This allows #: to have languages not yet ready for prime time while being able to access #: those pages in the admin backend. -FEINCMS_FRONTEND_LANGUAGES = getattr( - settings, - 'FEINCMS_FRONTEND_LANGUAGES', - None) +FEINCMS_FRONTEND_LANGUAGES = getattr(settings, "FEINCMS_FRONTEND_LANGUAGES", None) # ------------------------------------------------------------------------ diff --git a/feincms/extensions/__init__.py b/feincms/extensions/__init__.py index 853f27091..ad37b177f 100644 --- a/feincms/extensions/__init__.py +++ b/feincms/extensions/__init__.py @@ -1,10 +1,15 @@ from __future__ import absolute_import from .base import ( - ExtensionsMixin, Extension, ExtensionModelAdmin, - prefetch_modeladmin_get_queryset) + ExtensionsMixin, + Extension, + ExtensionModelAdmin, + prefetch_modeladmin_get_queryset, +) __all__ = ( - 'ExtensionsMixin', 'Extension', 'ExtensionModelAdmin', - 'prefetch_modeladmin_get_queryset', + "ExtensionsMixin", + "Extension", + "ExtensionModelAdmin", + "prefetch_modeladmin_get_queryset", ) diff --git a/feincms/extensions/base.py b/feincms/extensions/base.py index 31773ff6f..55a0ebde9 100644 --- a/feincms/extensions/base.py +++ b/feincms/extensions/base.py @@ -27,7 +27,7 @@ def register_extensions(cls, *extensions): sufficient. """ - if not hasattr(cls, '_extensions'): + if not hasattr(cls, "_extensions"): cls._extensions = [] cls._extensions_seen = [] @@ -46,32 +46,31 @@ def register_extensions(cls, *extensions): except (AttributeError, ImportError, ValueError): if not extension: raise ImproperlyConfigured( - '%s is not a valid extension for %s' % ( - ext, cls.__name__)) + "%s is not a valid extension for %s" % (ext, cls.__name__) + ) - if hasattr(extension, 'Extension'): + if hasattr(extension, "Extension"): extension = extension.Extension - elif hasattr(extension, 'register'): + elif hasattr(extension, "register"): extension = extension.register - elif hasattr(extension, '__call__'): + elif hasattr(extension, "__call__"): pass else: raise ImproperlyConfigured( - '%s is not a valid extension for %s' % ( - ext, cls.__name__)) + "%s is not a valid extension for %s" % (ext, cls.__name__) + ) if extension in cls._extensions_seen: continue cls._extensions_seen.append(extension) - if hasattr(extension, 'handle_model'): + if hasattr(extension, "handle_model"): cls._extensions.append(extension(cls)) else: - raise ImproperlyConfigured( - '%r is an invalid extension.' % extension) + raise ImproperlyConfigured("%r is an invalid extension." % extension) class Extension(object): @@ -79,8 +78,10 @@ def __init__(self, model, **kwargs): self.model = model for key, value in kwargs.items(): if not hasattr(self, key): - raise TypeError('%s() received an invalid keyword %r' % ( - self.__class__.__name__, key)) + raise TypeError( + "%s() received an invalid keyword %r" + % (self.__class__.__name__, key) + ) setattr(self, key, value) self.handle_model() @@ -98,26 +99,26 @@ def __init__(self, *args, **kwargs): self.initialize_extensions() def initialize_extensions(self): - if not hasattr(self, '_extensions_initialized'): + if not hasattr(self, "_extensions_initialized"): self._extensions_initialized = True - for extension in getattr(self.model, '_extensions', []): + for extension in getattr(self.model, "_extensions", []): extension.handle_modeladmin(self) def add_extension_options(self, *f): if self.fieldsets is None: return - if isinstance(f[-1], dict): # called with a fieldset + if isinstance(f[-1], dict): # called with a fieldset self.fieldsets.insert(self.fieldset_insertion_index, f) - f[1]['classes'] = list(f[1].get('classes', [])) - f[1]['classes'].append('collapse') - elif f: # assume called with "other" fields + f[1]["classes"] = list(f[1].get("classes", [])) + f[1]["classes"].append("collapse") + elif f: # assume called with "other" fields try: - self.fieldsets[1][1]['fields'].extend(f) + self.fieldsets[1][1]["fields"].extend(f) except IndexError: # Fall back to first fieldset if second does not exist # XXX This is really messy. - self.fieldsets[0][1]['fields'].extend(f) + self.fieldsets[0][1]["fields"].extend(f) def extend_list(self, attribute, iterable): extended = list(getattr(self, attribute, ())) @@ -129,12 +130,14 @@ def prefetch_modeladmin_get_queryset(modeladmin, *lookups): """ Wraps default modeladmin ``get_queryset`` to prefetch related lookups. """ + def do_wrap(f): @wraps(f) def wrapper(request, *args, **kwargs): qs = f(request, *args, **kwargs) qs = qs.prefetch_related(*lookups) return qs + return wrapper modeladmin.get_queryset = do_wrap(modeladmin.get_queryset) diff --git a/feincms/extensions/changedate.py b/feincms/extensions/changedate.py index cb21d288a..b470ff387 100644 --- a/feincms/extensions/changedate.py +++ b/feincms/extensions/changedate.py @@ -38,10 +38,14 @@ def dt_to_utc_timestamp(dt): class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('creation_date', models.DateTimeField( - _('creation date'), null=True, editable=False)) - self.model.add_to_class('modification_date', models.DateTimeField( - _('modification date'), null=True, editable=False)) + self.model.add_to_class( + "creation_date", + models.DateTimeField(_("creation date"), null=True, editable=False), + ) + self.model.add_to_class( + "modification_date", + models.DateTimeField(_("modification date"), null=True, editable=False), + ) self.model.last_modified = lambda p: p.modification_date @@ -51,16 +55,17 @@ def handle_model(self): # ------------------------------------------------------------------------ def last_modified_response_processor(page, request, response): # Don't include Last-Modified if we don't want to be cached - if "no-cache" in response.get('Cache-Control', ''): + if "no-cache" in response.get("Cache-Control", ""): return # If we already have a Last-Modified, take the later one last_modified = dt_to_utc_timestamp(page.last_modified()) - if response.has_header('Last-Modified'): + if response.has_header("Last-Modified"): last_modified = max( - last_modified, - mktime_tz(parsedate_tz(response['Last-Modified']))) + last_modified, mktime_tz(parsedate_tz(response["Last-Modified"])) + ) + + response["Last-Modified"] = http_date(last_modified) - response['Last-Modified'] = http_date(last_modified) # ------------------------------------------------------------------------ diff --git a/feincms/extensions/ct_tracker.py b/feincms/extensions/ct_tracker.py index 51308e5f8..9f263c535 100644 --- a/feincms/extensions/ct_tracker.py +++ b/feincms/extensions/ct_tracker.py @@ -46,34 +46,37 @@ def _fetch_content_type_counts(self): empty _ct_inventory. """ - if 'counts' not in self._cache: - if (self.item._ct_inventory and - self.item._ct_inventory.get('_version_', -1) == - INVENTORY_VERSION): + if "counts" not in self._cache: + if ( + self.item._ct_inventory + and self.item._ct_inventory.get("_version_", -1) == INVENTORY_VERSION + ): try: - self._cache['counts'] = self._from_inventory( - self.item._ct_inventory) + self._cache["counts"] = self._from_inventory( + self.item._ct_inventory + ) except KeyError: # It's possible that the inventory does not fit together # with the current models anymore, f.e. because a content # type has been removed. pass - if 'counts' not in self._cache: + if "counts" not in self._cache: super(TrackerContentProxy, self)._fetch_content_type_counts() - self.item._ct_inventory = self._to_inventory( - self._cache['counts']) + self.item._ct_inventory = self._to_inventory(self._cache["counts"]) self.item.__class__.objects.filter(id=self.item.id).update( - _ct_inventory=self.item._ct_inventory) + _ct_inventory=self.item._ct_inventory + ) # Run post save handler by hand - if hasattr(self.item, 'get_descendants'): + if hasattr(self.item, "get_descendants"): self.item.get_descendants(include_self=False).update( - _ct_inventory=None) - return self._cache['counts'] + _ct_inventory=None + ) + return self._cache["counts"] def _translation_map(self): cls = self.item.__class__ @@ -101,20 +104,20 @@ def _from_inventory(self, inventory): map = self._translation_map() - return dict((region, [ - (pk, map[-ct]) for pk, ct in items - ]) for region, items in inventory.items() if region != '_version_') + return dict( + (region, [(pk, map[-ct]) for pk, ct in items]) + for region, items in inventory.items() + if region != "_version_" + ) def _to_inventory(self, counts): map = self._translation_map() inventory = dict( - ( - region, - [(pk, map[ct]) for pk, ct in items], - ) for region, items in counts.items() + (region, [(pk, map[ct]) for pk, ct in items]) + for region, items in counts.items() ) - inventory['_version_'] = INVENTORY_VERSION + inventory["_version_"] = INVENTORY_VERSION return inventory @@ -151,12 +154,15 @@ def single_pre_save_handler(sender, instance, **kwargs): # ------------------------------------------------------------------------ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('_ct_inventory', JSONField( - _('content types'), editable=False, blank=True, null=True)) + self.model.add_to_class( + "_ct_inventory", + JSONField(_("content types"), editable=False, blank=True, null=True), + ) self.model.content_proxy_class = TrackerContentProxy pre_save.connect(single_pre_save_handler, sender=self.model) - if hasattr(self.model, 'get_descendants'): + if hasattr(self.model, "get_descendants"): post_save.connect(tree_post_save_handler, sender=self.model) + # ------------------------------------------------------------------------ diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index 39c26f6d5..bae2387d8 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -24,7 +24,7 @@ # ------------------------------------------------------------------------ -def format_date(d, if_none=''): +def format_date(d, if_none=""): """ Format a date in a nice human readable way: Omit the year if it's the current year. Also return a default value if no date is passed in. @@ -34,12 +34,12 @@ def format_date(d, if_none=''): return if_none now = timezone.now() - fmt = (d.year == now.year) and '%d.%m' or '%d.%m.%Y' + fmt = (d.year == now.year) and "%d.%m" or "%d.%m.%Y" return d.strftime(fmt) def latest_children(self): - return self.get_children().order_by('-publication_date') + return self.get_children().order_by("-publication_date") # ------------------------------------------------------------------------ @@ -70,8 +70,8 @@ def granular_now(n=None, default_tz=None): retval = timezone.make_aware(d, default_tz, is_dst=False) except TypeError: # Pre-Django 1.9 retval = timezone.make_aware( - datetime(n.year, n.month, n.day, n.hour + 1, rounded_minute), - default_tz) + datetime(n.year, n.month, n.day, n.hour + 1, rounded_minute), default_tz + ) return retval @@ -95,16 +95,19 @@ def datepublisher_response_processor(page, request, response): class Extension(extensions.Extension): def handle_model(self): self.model.add_to_class( - 'publication_date', - models.DateTimeField(_('publication date'), default=granular_now)) + "publication_date", + models.DateTimeField(_("publication date"), default=granular_now), + ) self.model.add_to_class( - 'publication_end_date', + "publication_end_date", models.DateTimeField( - _('publication end date'), - blank=True, null=True, - help_text=_( - 'Leave empty if the entry should stay active forever.'))) - self.model.add_to_class('latest_children', latest_children) + _("publication end date"), + blank=True, + null=True, + help_text=_("Leave empty if the entry should stay active forever."), + ), + ) + self.model.add_to_class("latest_children", latest_children) # Patch in rounding the pub and pub_end dates on save orig_save = self.model.save @@ -113,44 +116,52 @@ def granular_save(obj, *args, **kwargs): if obj.publication_date: obj.publication_date = granular_now(obj.publication_date) if obj.publication_end_date: - obj.publication_end_date = granular_now( - obj.publication_end_date) + obj.publication_end_date = granular_now(obj.publication_end_date) orig_save(obj, *args, **kwargs) + self.model.save = granular_save # Append publication date active check - if hasattr(self.model._default_manager, 'add_to_active_filters'): + if hasattr(self.model._default_manager, "add_to_active_filters"): self.model._default_manager.add_to_active_filters( lambda queryset: queryset.filter( - Q(publication_date__lte=granular_now()) & - (Q(publication_end_date__isnull=True) | - Q(publication_end_date__gt=granular_now()))), - key='datepublisher', + Q(publication_date__lte=granular_now()) + & ( + Q(publication_end_date__isnull=True) + | Q(publication_end_date__gt=granular_now()) + ) + ), + key="datepublisher", ) # Processor to patch up response headers for expiry date - self.model.register_response_processor( - datepublisher_response_processor) + self.model.register_response_processor(datepublisher_response_processor) def handle_modeladmin(self, modeladmin): def datepublisher_admin(self, obj): - return mark_safe('%s – %s' % ( - format_date(obj.publication_date), - format_date(obj.publication_end_date, '∞'), - )) - datepublisher_admin.short_description = _('visible from - to') + return mark_safe( + "%s – %s" + % ( + format_date(obj.publication_date), + format_date(obj.publication_end_date, "∞"), + ) + ) + + datepublisher_admin.short_description = _("visible from - to") modeladmin.__class__.datepublisher_admin = datepublisher_admin try: - pos = modeladmin.list_display.index('is_visible_admin') + pos = modeladmin.list_display.index("is_visible_admin") except ValueError: pos = len(modeladmin.list_display) - modeladmin.list_display.insert(pos + 1, 'datepublisher_admin') + modeladmin.list_display.insert(pos + 1, "datepublisher_admin") + + modeladmin.add_extension_options( + _("Date-based publishing"), + {"fields": ["publication_date", "publication_end_date"]}, + ) - modeladmin.add_extension_options(_('Date-based publishing'), { - 'fields': ['publication_date', 'publication_end_date'], - }) # ------------------------------------------------------------------------ diff --git a/feincms/extensions/featured.py b/feincms/extensions/featured.py index 139edcdda..9d5f2e92d 100644 --- a/feincms/extensions/featured.py +++ b/feincms/extensions/featured.py @@ -13,15 +13,10 @@ class Extension(extensions.Extension): def handle_model(self): self.model.add_to_class( - 'featured', - models.BooleanField( - _('featured'), - default=False, - ), + "featured", models.BooleanField(_("featured"), default=False) ) def handle_modeladmin(self, modeladmin): - modeladmin.add_extension_options(_('Featured'), { - 'fields': ('featured',), - 'classes': ('collapse',), - }) + modeladmin.add_extension_options( + _("Featured"), {"fields": ("featured",), "classes": ("collapse",)} + ) diff --git a/feincms/extensions/seo.py b/feincms/extensions/seo.py index f71d9f5f3..3f01152a0 100644 --- a/feincms/extensions/seo.py +++ b/feincms/extensions/seo.py @@ -12,24 +12,31 @@ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('meta_keywords', models.TextField( - _('meta keywords'), - blank=True, - help_text=_('Keywords are ignored by most search engines.'))) - self.model.add_to_class('meta_description', models.TextField( - _('meta description'), - blank=True, - help_text=_('This text is displayed on the search results page. ' - 'It is however not used for the SEO ranking. ' - 'Text longer than 140 characters is truncated.'))) + self.model.add_to_class( + "meta_keywords", + models.TextField( + _("meta keywords"), + blank=True, + help_text=_("Keywords are ignored by most search engines."), + ), + ) + self.model.add_to_class( + "meta_description", + models.TextField( + _("meta description"), + blank=True, + help_text=_( + "This text is displayed on the search results page. " + "It is however not used for the SEO ranking. " + "Text longer than 140 characters is truncated." + ), + ), + ) def handle_modeladmin(self, modeladmin): - modeladmin.extend_list( - 'search_fields', - ['meta_keywords', 'meta_description'], - ) + modeladmin.extend_list("search_fields", ["meta_keywords", "meta_description"]) - modeladmin.add_extension_options(_('Search engine optimization'), { - 'fields': ('meta_keywords', 'meta_description'), - 'classes': ('collapse',), - }) + modeladmin.add_extension_options( + _("Search engine optimization"), + {"fields": ("meta_keywords", "meta_description"), "classes": ("collapse",)}, + ) diff --git a/feincms/extensions/translations.py b/feincms/extensions/translations.py index 4c37cda1d..bbcda6d15 100644 --- a/feincms/extensions/translations.py +++ b/feincms/extensions/translations.py @@ -36,7 +36,7 @@ logger = logging.getLogger(__name__) LANGUAGE_COOKIE_NAME = django_settings.LANGUAGE_COOKIE_NAME -if hasattr(translation, 'LANGUAGE_SESSION_KEY'): +if hasattr(translation, "LANGUAGE_SESSION_KEY"): LANGUAGE_SESSION_KEY = translation.LANGUAGE_SESSION_KEY else: # Django 1.6 @@ -50,8 +50,10 @@ def user_has_language_set(request): This is taken later on as an indication that we should not mess with the site's language settings, after all, the user's decision is what counts. """ - if (hasattr(request, 'session') and - request.session.get(LANGUAGE_SESSION_KEY) is not None): + if ( + hasattr(request, "session") + and request.session.get(LANGUAGE_SESSION_KEY) is not None + ): return True if LANGUAGE_COOKIE_NAME in request.COOKIES: return True @@ -91,19 +93,18 @@ def translation_set_language(request, select_language): translation.activate(select_language) request.LANGUAGE_CODE = translation.get_language() - if hasattr(request, 'session'): + if hasattr(request, "session"): # User has a session, then set this language there if select_language != request.session.get(LANGUAGE_SESSION_KEY): request.session[LANGUAGE_SESSION_KEY] = select_language - elif request.method == 'GET' and not fallback: + elif request.method == "GET" and not fallback: # No session is active. We need to set a cookie for the language # so that it persists when users change their location to somewhere # not under the control of the CMS. # Only do this when request method is GET (mainly, do not abort # POST requests) response = HttpResponseRedirect(request.get_full_path()) - response.set_cookie( - str(LANGUAGE_COOKIE_NAME), select_language) + response.set_cookie(str(LANGUAGE_COOKIE_NAME), select_language) return response @@ -118,8 +119,8 @@ def translations_request_processor_explicit(page, request): desired_language = page.language # ...except if the user explicitely wants to switch language - if 'set_language' in request.GET: - desired_language = request.GET['set_language'] + if "set_language" in request.GET: + desired_language = request.GET["set_language"] # ...or the user already has explicitely set a language, bail out and # don't change it for them behind their back elif user_has_language_set(request): @@ -131,7 +132,7 @@ def translations_request_processor_explicit(page, request): # ------------------------------------------------------------------------ def translations_request_processor_standard(page, request): # If this page is just a redirect, don't do any language specific setup - if getattr(page, 'redirect_to', None): + if getattr(page, "redirect_to", None): return if page.language == translation.get_language(): @@ -142,51 +143,54 @@ def translations_request_processor_standard(page, request): # ------------------------------------------------------------------------ def get_current_language_code(request): - language_code = getattr(request, 'LANGUAGE_CODE', None) + language_code = getattr(request, "LANGUAGE_CODE", None) if language_code is None: logger.warning( "Could not access request.LANGUAGE_CODE. Is 'django.middleware." - "locale.LocaleMiddleware' in MIDDLEWARE_CLASSES?") + "locale.LocaleMiddleware' in MIDDLEWARE_CLASSES?" + ) return language_code # ------------------------------------------------------------------------ class Extension(extensions.Extension): - def handle_model(self): cls = self.model cls.add_to_class( - 'language', + "language", models.CharField( - _('language'), + _("language"), max_length=10, choices=django_settings.LANGUAGES, - default=django_settings.LANGUAGES[0][0])) + default=django_settings.LANGUAGES[0][0], + ), + ) cls.add_to_class( - 'translation_of', + "translation_of", models.ForeignKey( - 'self', + "self", on_delete=models.CASCADE, - blank=True, null=True, verbose_name=_('translation of'), - related_name='translations', - limit_choices_to={'language': django_settings.LANGUAGES[0][0]}, - help_text=_( - 'Leave this empty for entries in the primary language.'), - ) + blank=True, + null=True, + verbose_name=_("translation of"), + related_name="translations", + limit_choices_to={"language": django_settings.LANGUAGES[0][0]}, + help_text=_("Leave this empty for entries in the primary language."), + ), ) - if hasattr(cls, 'register_request_processor'): + if hasattr(cls, "register_request_processor"): if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT": cls.register_request_processor( - translations_request_processor_explicit, - key='translations') + translations_request_processor_explicit, key="translations" + ) else: # STANDARD cls.register_request_processor( - translations_request_processor_standard, - key='translations') + translations_request_processor_standard, key="translations" + ) - if hasattr(cls, 'get_redirect_to_target'): + if hasattr(cls, "get_redirect_to_target"): original_get_redirect_to_target = cls.get_redirect_to_target @monkeypatch_method(cls) @@ -199,7 +203,7 @@ def get_redirect_to_target(self, request=None): redirection. """ target = original_get_redirect_to_target(self, request) - if target and target.find('//') == -1: + if target and target.find("//") == -1: # Not an offsite link http://bla/blubb try: page = cls.objects.page_for_path(target) @@ -217,9 +221,10 @@ def available_translations(self): if not self.id: # New, unsaved pages have no translations return [] - if hasattr(cls.objects, 'apply_active_filters'): + if hasattr(cls.objects, "apply_active_filters"): filter_active = cls.objects.apply_active_filters else: + def filter_active(queryset): return queryset @@ -228,9 +233,10 @@ def filter_active(queryset): elif self.translation_of: # reuse prefetched queryset, do not filter it res = [ - t for t - in filter_active(self.translation_of.translations.all()) - if t.language != self.language] + t + for t in filter_active(self.translation_of.translations.all()) + if t.language != self.language + ] res.insert(0, self.translation_of) return res else: @@ -244,7 +250,10 @@ def get_original_translation(self, *args, **kwargs): return self.translation_of logger.debug( "Page pk=%d (%s) has no primary language translation (%s)", - self.pk, self.language, django_settings.LANGUAGES[0][0]) + self.pk, + self.language, + django_settings.LANGUAGES[0][0], + ) return self @monkeypatch_property(cls) @@ -253,12 +262,12 @@ def original_translation(self): @monkeypatch_method(cls) def get_translation(self, language): - return self.original_translation.translations.get( - language=language) + return self.original_translation.translations.get(language=language) def handle_modeladmin(self, modeladmin): extensions.prefetch_modeladmin_get_queryset( - modeladmin, 'translation_of__translations', 'translations') + modeladmin, "translation_of__translations", "translations" + ) def available_translations_admin(self, page): # Do not use available_translations() because we don't care @@ -268,10 +277,7 @@ def available_translations_admin(self, page): if page.translation_of: translations.append(page.translation_of) translations.extend(page.translation_of.translations.all()) - translations = { - p.language: p.id - for p in translations - } + translations = {p.language: p.id for p in translations} links = [] @@ -280,33 +286,30 @@ def available_translations_admin(self, page): continue if key in translations: - links.append('%s' % ( - translations[key], _('Edit translation'), key.upper())) + links.append( + '%s' + % (translations[key], _("Edit translation"), key.upper()) + ) else: links.append( '%s' % ( - page.id, - key, - _('Create translation'), - key.upper() - ) + '%s&language=%s" title="%s">%s' + % (page.id, key, _("Create translation"), key.upper()) ) - return mark_safe(' | '.join(links)) + return mark_safe(" | ".join(links)) - available_translations_admin.short_description = _('translations') - modeladmin.__class__.available_translations_admin =\ - available_translations_admin + available_translations_admin.short_description = _("translations") + modeladmin.__class__.available_translations_admin = available_translations_admin - if hasattr(modeladmin, 'add_extension_options'): - modeladmin.add_extension_options('language', 'translation_of') + if hasattr(modeladmin, "add_extension_options"): + modeladmin.add_extension_options("language", "translation_of") modeladmin.extend_list( - 'list_display', - ['language', 'available_translations_admin'], + "list_display", ["language", "available_translations_admin"] ) - modeladmin.extend_list('list_filter', ['language']) - modeladmin.extend_list('raw_id_fields', ['translation_of']) + modeladmin.extend_list("list_filter", ["language"]) + modeladmin.extend_list("raw_id_fields", ["translation_of"]) + # ------------------------------------------------------------------------ diff --git a/feincms/management/commands/medialibrary_orphans.py b/feincms/management/commands/medialibrary_orphans.py index 7a27a56de..d1c1eb00b 100644 --- a/feincms/management/commands/medialibrary_orphans.py +++ b/feincms/management/commands/medialibrary_orphans.py @@ -12,10 +12,10 @@ class Command(NoArgsCommand): help = "Prints all orphaned files in the `media/medialibrary` folder" def handle_noargs(self, **options): - mediafiles = list(MediaFile.objects.values_list('file', flat=True)) + mediafiles = list(MediaFile.objects.values_list("file", flat=True)) # TODO make this smarter, and take MEDIA_ROOT into account - for base, dirs, files in os.walk('media/medialibrary'): + for base, dirs, files in os.walk("media/medialibrary"): for f in files: full = os.path.join(base[6:], f) if force_text(full) not in mediafiles: diff --git a/feincms/management/commands/medialibrary_to_filer.py b/feincms/management/commands/medialibrary_to_filer.py index ff34c8d41..2ac3fefec 100644 --- a/feincms/management/commands/medialibrary_to_filer.py +++ b/feincms/management/commands/medialibrary_to_filer.py @@ -17,31 +17,31 @@ PageFilerImageContent = Page.content_type_for(FilerImageContent) -assert all(( - PageMediaFileContent, - PageFilerFileContent, - PageFilerImageContent)), 'Not all required models available' +assert all( + (PageMediaFileContent, PageFilerFileContent, PageFilerImageContent) +), "Not all required models available" class Command(NoArgsCommand): help = "Migrate the medialibrary and contents to django-filer" def handle_noargs(self, **options): - user = User.objects.order_by('pk')[0] + user = User.objects.order_by("pk")[0] count = MediaFile.objects.count() - for i, mediafile in enumerate(MediaFile.objects.order_by('pk')): - model = Image if mediafile.type == 'image' else File - content_model = PageFilerImageContent if mediafile.type == 'image' else PageFilerFileContent # noqa + for i, mediafile in enumerate(MediaFile.objects.order_by("pk")): + model = Image if mediafile.type == "image" else File + content_model = ( + PageFilerImageContent + if mediafile.type == "image" + else PageFilerFileContent + ) # noqa filerfile = model.objects.create( owner=user, original_filename=mediafile.file.name, - file=DjangoFile( - mediafile.file.file, - name=mediafile.file.name, - ), + file=DjangoFile(mediafile.file.file, name=mediafile.file.name), ) contents = PageMediaFileContent.objects.filter(mediafile=mediafile) @@ -58,6 +58,6 @@ def handle_noargs(self, **options): content.delete() if not i % 10: - self.stdout.write('%s / %s files\n' % (i, count)) + self.stdout.write("%s / %s files\n" % (i, count)) - self.stdout.write('%s / %s files\n' % (count, count)) + self.stdout.write("%s / %s files\n" % (count, count)) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index b99291d02..f290daa50 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -19,12 +19,10 @@ class Command(BaseCommand): - help = ( - "Run this manually to rebuild your mptt pointers. Only use in" - " emergencies.") + help = "Run this manually to rebuild your mptt pointers. Only use in emergencies." def handle_noargs(self, **options): - self.handle(**options) + self.handle(**options) def handle(self, **options): self.stdout.write("Rebuilding MPTT pointers for Page") diff --git a/feincms/models.py b/feincms/models.py index 0e3d49b2c..0bcddabfc 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -36,7 +36,7 @@ class Region(object): def __init__(self, key, title, *args): self.key = key self.title = title - self.inherited = args and args[0] == 'inherited' or False + self.inherited = args and args[0] == "inherited" or False self._content_types = [] def __str__(self): @@ -50,8 +50,7 @@ def content_types(self): """ return [ - (ct.__name__.lower(), ct._meta.verbose_name) - for ct in self._content_types + (ct.__name__.lower(), ct._meta.verbose_name) for ct in self._content_types ] @@ -62,8 +61,7 @@ class Template(object): CMS object, most commonly a page. """ - def __init__(self, title, path, regions, key=None, preview_image=None, - **kwargs): + def __init__(self, title, path, regions, key=None, preview_image=None, **kwargs): # The key is what will be stored in the database. If key is undefined # use the template path as fallback. if not key: @@ -73,10 +71,10 @@ def __init__(self, title, path, regions, key=None, preview_image=None, self.title = title self.path = path self.preview_image = preview_image - self.singleton = kwargs.get('singleton', False) - self.child_template = kwargs.get('child_template', None) - self.enforce_leaf = kwargs.get('enforce_leaf', False) - self.urlconf = kwargs.get('urlconf', None) + self.singleton = kwargs.get("singleton", False) + self.child_template = kwargs.get("child_template", None) + self.enforce_leaf = kwargs.get("enforce_leaf", False) + self.urlconf = kwargs.get("urlconf", None) def _make_region(data): if isinstance(data, Region): @@ -105,9 +103,7 @@ def __init__(self, item): item._needs_content_types() self.item = item self.db = item._state.db - self._cache = { - 'cts': {}, - } + self._cache = {"cts": {}} def _inherit_from(self): """ @@ -118,8 +114,7 @@ def _inherit_from(self): is good enough (tm) for pages. """ - return self.item.get_ancestors(ascending=True).values_list( - 'pk', flat=True) + return self.item.get_ancestors(ascending=True).values_list("pk", flat=True) def _fetch_content_type_counts(self): """ @@ -138,7 +133,7 @@ def _fetch_content_type_counts(self): } """ - if 'counts' not in self._cache: + if "counts" not in self._cache: counts = self._fetch_content_type_count_helper(self.item.pk) empty_inherited_regions = set() @@ -149,7 +144,8 @@ def _fetch_content_type_counts(self): if empty_inherited_regions: for parent in self._inherit_from(): parent_counts = self._fetch_content_type_count_helper( - parent, regions=tuple(empty_inherited_regions)) + parent, regions=tuple(empty_inherited_regions) + ) counts.update(parent_counts) for key in parent_counts.keys(): @@ -158,28 +154,27 @@ def _fetch_content_type_counts(self): if not empty_inherited_regions: break - self._cache['counts'] = counts - return self._cache['counts'] + self._cache["counts"] = counts + return self._cache["counts"] def _fetch_content_type_count_helper(self, pk, regions=None): - tmpl = [ - 'SELECT %d AS ct_idx, region, COUNT(id) FROM %s WHERE parent_id=%s' - ] + tmpl = ["SELECT %d AS ct_idx, region, COUNT(id) FROM %s WHERE parent_id=%s"] args = [] if regions: - tmpl.append( - 'AND region IN (' + ','.join(['%%s'] * len(regions)) + ')') + tmpl.append("AND region IN (" + ",".join(["%%s"] * len(regions)) + ")") args.extend(regions * len(self.item._feincms_content_types)) - tmpl.append('GROUP BY region') - tmpl = ' '.join(tmpl) + tmpl.append("GROUP BY region") + tmpl = " ".join(tmpl) - sql = ' UNION '.join([ - tmpl % (idx, cls._meta.db_table, pk) - for idx, cls in enumerate(self.item._feincms_content_types) - ]) - sql = 'SELECT * FROM ( ' + sql + ' ) AS ct ORDER BY ct_idx' + sql = " UNION ".join( + [ + tmpl % (idx, cls._meta.db_table, pk) + for idx, cls in enumerate(self.item._feincms_content_types) + ] + ) + sql = "SELECT * FROM ( " + sql + " ) AS ct ORDER BY ct_idx" cursor = connections[self.db].cursor() cursor.execute(sql, args) @@ -200,55 +195,56 @@ def _populate_content_type_caches(self, types): for region, counts in self._fetch_content_type_counts().items(): for pk, ct_idx in counts: counts_by_type.setdefault( - self.item._feincms_content_types[ct_idx], - [], + self.item._feincms_content_types[ct_idx], [] ).append((region, pk)) # Resolve abstract to concrete content types content_types = ( - cls for cls in self.item._feincms_content_types + cls + for cls in self.item._feincms_content_types if issubclass(cls, tuple(types)) ) for cls in content_types: counts = counts_by_type.get(cls) - if cls not in self._cache['cts']: + if cls not in self._cache["cts"]: if counts: - self._cache['cts'][cls] = list(cls.get_queryset(reduce( - operator.or_, - (Q(region=r[0], parent=r[1]) for r in counts) - ))) + self._cache["cts"][cls] = list( + cls.get_queryset( + reduce( + operator.or_, + (Q(region=r[0], parent=r[1]) for r in counts), + ) + ) + ) else: - self._cache['cts'][cls] = [] + self._cache["cts"][cls] = [] # share this content proxy object between all content items # so that each can use obj.parent.content to determine its # relationship to its siblings, etc. - for cls, objects in self._cache['cts'].items(): + for cls, objects in self._cache["cts"].items(): for obj in objects: - setattr(obj.parent, '_content_proxy', self) + setattr(obj.parent, "_content_proxy", self) def _fetch_regions(self): """ Fetches all content types and group content types into regions """ - if 'regions' not in self._cache: - self._populate_content_type_caches( - self.item._feincms_content_types) + if "regions" not in self._cache: + self._populate_content_type_caches(self.item._feincms_content_types) contents = {} - for cls, content_list in self._cache['cts'].items(): + for cls, content_list in self._cache["cts"].items(): for instance in content_list: contents.setdefault(instance.region, []).append(instance) - self._cache['regions'] = dict( - ( - region, - sorted(instances, key=lambda c: c.ordering), - ) for region, instances in contents.items() + self._cache["regions"] = dict( + (region, sorted(instances, key=lambda c: c.ordering)) + for region, instances in contents.items() ) - return self._cache['regions'] + return self._cache["regions"] def all_of_type(self, type_or_tuple): """ @@ -262,11 +258,11 @@ def all_of_type(self, type_or_tuple): """ content_list = [] - if not hasattr(type_or_tuple, '__iter__'): + if not hasattr(type_or_tuple, "__iter__"): type_or_tuple = (type_or_tuple,) self._populate_content_type_caches(type_or_tuple) - for type, contents in self._cache['cts'].items(): + for type, contents in self._cache["cts"].items(): if any(issubclass(type, t) for t in type_or_tuple): content_list.extend(contents) @@ -277,16 +273,17 @@ def _get_media(self): Collect the media files of all content types of the current object """ - if 'media' not in self._cache: + if "media" not in self._cache: media = Media() for contents in self._fetch_regions().values(): for content in contents: - if hasattr(content, 'media'): + if hasattr(content, "media"): media = media + content.media - self._cache['media'] = media - return self._cache['media'] + self._cache["media"] = media + return self._cache["media"] + media = property(_get_media) def __getattr__(self, attr): @@ -297,7 +294,7 @@ def __getattr__(self, attr): has the inherited flag set, this method will go up the ancestor chain until either some item contents have found or no ancestors are left. """ - if (attr.startswith('__')): + if attr.startswith("__"): raise AttributeError # Do not trigger loading of real content type models if not necessary @@ -337,15 +334,15 @@ def register_regions(cls, *regions): ) """ - if hasattr(cls, 'template'): + if hasattr(cls, "template"): warnings.warn( - 'Ignoring second call to register_regions.', - RuntimeWarning) + "Ignoring second call to register_regions.", RuntimeWarning + ) return # implicitly creates a dummy template object -- the item editor # depends on the presence of a template. - cls.template = Template('', '', regions) + cls.template = Template("", "", regions) cls._feincms_all_regions = cls.template.regions @classmethod @@ -374,7 +371,7 @@ def register_templates(cls, *templates): }) """ - if not hasattr(cls, '_feincms_templates'): + if not hasattr(cls, "_feincms_templates"): cls._feincms_templates = OrderedDict() cls.TEMPLATES_CHOICES = [] @@ -387,21 +384,33 @@ def register_templates(cls, *templates): instances[template.key] = template try: - field = next(iter( - field for field in cls._meta.local_fields - if field.name == 'template_key')) + field = next( + iter( + field + for field in cls._meta.local_fields + if field.name == "template_key" + ) + ) except (StopIteration,): cls.add_to_class( - 'template_key', - models.CharField(_('template'), max_length=255, choices=( - # Dummy choice to trick Django. Cannot be empty, - # otherwise admin.E023 happens. - ('__dummy', '__dummy'), - )) + "template_key", + models.CharField( + _("template"), + max_length=255, + choices=( + # Dummy choice to trick Django. Cannot be empty, + # otherwise admin.E023 happens. + ("__dummy", "__dummy"), + ), + ), + ) + field = next( + iter( + field + for field in cls._meta.local_fields + if field.name == "template_key" + ) ) - field = next(iter( - field for field in cls._meta.local_fields - if field.name == 'template_key')) def _template(self): ensure_completely_loaded() @@ -412,12 +421,13 @@ def _template(self): # return first template as a fallback if the template # has changed in-between return self._feincms_templates[ - list(self._feincms_templates.keys())[0]] + list(self._feincms_templates.keys())[0] + ] cls.template = property(_template) cls.TEMPLATE_CHOICES = [ - (template_.key, template_.title,) + (template_.key, template_.title) for template_ in cls._feincms_templates.values() ] try: @@ -445,7 +455,7 @@ def content(self): ``content_proxy_class`` member variable. """ - if not hasattr(self, '_content_proxy'): + if not hasattr(self, "_content_proxy"): self._content_proxy = self.content_proxy_class(self) return self._content_proxy @@ -472,19 +482,20 @@ def _create_content_base(cls): class Meta: abstract = True app_label = cls._meta.app_label - ordering = ['ordering'] + ordering = ["ordering"] def __str__(self): return ( - '%s, region=%s,' - ' ordering=%d>') % ( + "%s, region=%s," " ordering=%d>" + ) % ( self.__class__.__name__, self.pk, self.parent.__class__.__name__, self.parent.pk, self.parent, self.region, - self.ordering) + self.ordering, + ) def render(self, **kwargs): """ @@ -495,7 +506,7 @@ def render(self, **kwargs): time instead of adding region-specific render methods. """ - render_fn = getattr(self, 'render_%s' % self.region, None) + render_fn = getattr(self, "render_%s" % self.region, None) if render_fn: return render_fn(**kwargs) @@ -512,31 +523,33 @@ def get_queryset(cls, filter_args): # needs to know where a model comes # from, therefore we ensure that the # module is always known. - '__module__': cls.__module__, - '__str__': __str__, - 'render': render, - 'get_queryset': classmethod(get_queryset), - 'Meta': Meta, - 'parent': models.ForeignKey( - cls, related_name='%(class)s_set', - on_delete=models.CASCADE), - 'region': models.CharField(max_length=255), - 'ordering': models.IntegerField(_('ordering'), default=0), + "__module__": cls.__module__, + "__str__": __str__, + "render": render, + "get_queryset": classmethod(get_queryset), + "Meta": Meta, + "parent": models.ForeignKey( + cls, related_name="%(class)s_set", on_delete=models.CASCADE + ), + "region": models.CharField(max_length=255), + "ordering": models.IntegerField(_("ordering"), default=0), } # create content base type and save reference on CMS class - name = '_Internal%sContentTypeBase' % cls.__name__ + name = "_Internal%sContentTypeBase" % cls.__name__ if hasattr(sys.modules[cls.__module__], name): warnings.warn( - 'The class %s.%s has the same name as the class that ' - 'FeinCMS auto-generates based on %s.%s. To avoid database' - 'errors and import clashes, rename one of these classes.' + "The class %s.%s has the same name as the class that " + "FeinCMS auto-generates based on %s.%s. To avoid database" + "errors and import clashes, rename one of these classes." % (cls.__module__, name, cls.__module__, cls.__name__), - RuntimeWarning) + RuntimeWarning, + ) cls._feincms_content_model = python_2_unicode_compatible( - type(str(name), (models.Model,), attrs)) + type(str(name), (models.Model,), attrs) + ) # list of concrete content types cls._feincms_content_types = [] @@ -557,23 +570,24 @@ def get_queryset(cls, filter_args): # list of item editor context processors, will be extended by # content types - if hasattr(cls, 'feincms_item_editor_context_processors'): + if hasattr(cls, "feincms_item_editor_context_processors"): cls.feincms_item_editor_context_processors = list( - cls.feincms_item_editor_context_processors) + cls.feincms_item_editor_context_processors + ) else: cls.feincms_item_editor_context_processors = [] # list of templates which should be included in the item editor, # will be extended by content types - if hasattr(cls, 'feincms_item_editor_includes'): + if hasattr(cls, "feincms_item_editor_includes"): cls.feincms_item_editor_includes = dict( - cls.feincms_item_editor_includes) + cls.feincms_item_editor_includes + ) else: cls.feincms_item_editor_includes = {} @classmethod - def create_content_type(cls, model, regions=None, class_name=None, - **kwargs): + def create_content_type(cls, model, regions=None, class_name=None, **kwargs): """ This is the method you'll use to create concrete content types. @@ -622,14 +636,19 @@ def create_content_type(cls, model, regions=None, class_name=None, # content types with the same class name because of related_name # clashes try: - getattr(cls, '%s_set' % class_name.lower()) + getattr(cls, "%s_set" % class_name.lower()) warnings.warn( - 'Cannot create content type using %s.%s for %s.%s,' - ' because %s_set is already taken.' % ( - model.__module__, class_name, - cls.__module__, cls.__name__, - class_name.lower()), - RuntimeWarning) + "Cannot create content type using %s.%s for %s.%s," + " because %s_set is already taken." + % ( + model.__module__, + class_name, + cls.__module__, + cls.__name__, + class_name.lower(), + ), + RuntimeWarning, + ) return except AttributeError: # everything ok @@ -637,16 +656,16 @@ def create_content_type(cls, model, regions=None, class_name=None, if not model._meta.abstract: raise ImproperlyConfigured( - 'Cannot create content type from' - ' non-abstract model (yet).') + "Cannot create content type from" " non-abstract model (yet)." + ) - if not hasattr(cls, '_feincms_content_model'): + if not hasattr(cls, "_feincms_content_model"): cls._create_content_base() feincms_content_base = cls._feincms_content_model class Meta(feincms_content_base.Meta): - db_table = '%s_%s' % (cls._meta.db_table, class_name.lower()) + db_table = "%s_%s" % (cls._meta.db_table, class_name.lower()) verbose_name = model._meta.verbose_name verbose_name_plural = model._meta.verbose_name_plural permissions = model._meta.permissions @@ -659,26 +678,21 @@ class Meta(feincms_content_base.Meta): # content type may be used by several CMS # base models at the same time (f.e. in # the blog and the page module). - '__module__': cls.__module__, - 'Meta': Meta, + "__module__": cls.__module__, + "Meta": Meta, } - new_type = type( - str(class_name), - (model, feincms_content_base,), - attrs, - ) + new_type = type(str(class_name), (model, feincms_content_base), attrs) cls._feincms_content_types.append(new_type) - if hasattr(getattr(new_type, 'process', None), '__call__'): + if hasattr(getattr(new_type, "process", None), "__call__"): cls._feincms_content_types_with_process.append(new_type) - if hasattr(getattr(new_type, 'finalize', None), '__call__'): + if hasattr(getattr(new_type, "finalize", None), "__call__"): cls._feincms_content_types_with_finalize.append(new_type) # content types can be limited to a subset of regions if not regions: - regions = set([ - region.key for region in cls._feincms_all_regions]) + regions = set([region.key for region in cls._feincms_all_regions]) for region in cls._feincms_all_regions: if region.key in regions: @@ -689,7 +703,7 @@ class Meta(feincms_content_base.Meta): # f.e. for the update_rsscontent management command, which needs to # find all concrete RSSContent types, so that the RSS feeds can be # fetched - if not hasattr(model, '_feincms_content_models'): + if not hasattr(model, "_feincms_content_models"): model._feincms_content_models = [] model._feincms_content_models.append(new_type) @@ -699,36 +713,38 @@ class Meta(feincms_content_base.Meta): # Handle optgroup argument for grouping content types in the item # editor - optgroup = kwargs.pop('optgroup', None) + optgroup = kwargs.pop("optgroup", None) if optgroup: new_type.optgroup = optgroup # customization hook. - if hasattr(new_type, 'initialize_type'): + if hasattr(new_type, "initialize_type"): new_type.initialize_type(**kwargs) else: for k, v in kwargs.items(): setattr(new_type, k, v) # collect item editor context processors from the content type - if hasattr(model, 'feincms_item_editor_context_processors'): + if hasattr(model, "feincms_item_editor_context_processors"): cls.feincms_item_editor_context_processors.extend( - model.feincms_item_editor_context_processors) + model.feincms_item_editor_context_processors + ) # collect item editor includes from the content type - if hasattr(model, 'feincms_item_editor_includes'): + if hasattr(model, "feincms_item_editor_includes"): for key, incls in model.feincms_item_editor_includes.items(): - cls.feincms_item_editor_includes.setdefault( - key, set()).update(incls) + cls.feincms_item_editor_includes.setdefault(key, set()).update( + incls + ) ensure_completely_loaded(force=True) return new_type @property def _django_content_type(self): - if not getattr(self, '_cached_django_content_type', None): - self.__class__._cached_django_content_type = ( - ContentType.objects.get_for_model(self)) + if not getattr(self, "_cached_django_content_type", None): + ct = ContentType.objects.get_for_model(self) + self.__class__._cached_django_content_type = ct return self.__class__._cached_django_content_type @classmethod @@ -740,8 +756,10 @@ def content_type_for(cls, model): concrete_type = Page.content_type_for(VideoContent) """ - if (not hasattr(cls, '_feincms_content_types') or - not cls._feincms_content_types): + if ( + not hasattr(cls, "_feincms_content_types") + or not cls._feincms_content_types + ): return None for type in cls._feincms_content_types: @@ -756,10 +774,11 @@ def _needs_templates(cls): # helper which can be used to ensure that either register_regions # or register_templates has been executed before proceeding - if not hasattr(cls, 'template'): + if not hasattr(cls, "template"): raise ImproperlyConfigured( - 'You need to register at least one' - ' template or one region on %s.' % cls.__name__) + "You need to register at least one" + " template or one region on %s." % cls.__name__ + ) @classmethod def _needs_content_types(cls): @@ -767,10 +786,11 @@ def _needs_content_types(cls): # Check whether any content types have been created for this base # class - if not getattr(cls, '_feincms_content_types', None): + if not getattr(cls, "_feincms_content_types", None): raise ImproperlyConfigured( - 'You need to create at least one' - ' content type for the %s model.' % cls.__name__) + "You need to create at least one" + " content type for the %s model." % cls.__name__ + ) def copy_content_from(self, obj): """ @@ -781,8 +801,7 @@ def copy_content_from(self, obj): for cls in self._feincms_content_types: for content in cls.objects.filter(parent=obj): - new = copy_model_instance( - content, exclude=('id', 'parent')) + new = copy_model_instance(content, exclude=("id", "parent")) new.parent = self new.save() @@ -810,7 +829,7 @@ def register_with_reversion(cls): follow = [] for content_type in cls._feincms_content_types: - follow.append('%s_set' % content_type.__name__.lower()) + follow.append("%s_set" % content_type.__name__.lower()) register(content_type) register(cls, follow=follow) diff --git a/feincms/module/extensions/changedate.py b/feincms/module/extensions/changedate.py index dd543dbbc..fdfd93475 100644 --- a/feincms/module/extensions/changedate.py +++ b/feincms/module/extensions/changedate.py @@ -6,6 +6,8 @@ from feincms.extensions.changedate import * warnings.warn( - 'Import %(name)s from feincms.extensions.%(name)s' % { - 'name': __name__.split('.')[-1], - }, DeprecationWarning, stacklevel=2) + "Import %(name)s from feincms.extensions.%(name)s" + % {"name": __name__.split(".")[-1]}, + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index 7b94fd55f..f810b346e 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -6,6 +6,8 @@ from feincms.extensions.ct_tracker import * warnings.warn( - 'Import %(name)s from feincms.extensions.%(name)s' % { - 'name': __name__.split('.')[-1], - }, DeprecationWarning, stacklevel=2) + "Import %(name)s from feincms.extensions.%(name)s" + % {"name": __name__.split(".")[-1]}, + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 44fed5edb..313568d74 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -6,6 +6,8 @@ from feincms.extensions.datepublisher import * warnings.warn( - 'Import %(name)s from feincms.extensions.%(name)s' % { - 'name': __name__.split('.')[-1], - }, DeprecationWarning, stacklevel=2) + "Import %(name)s from feincms.extensions.%(name)s" + % {"name": __name__.split(".")[-1]}, + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index 05b59a87a..7713d026b 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -6,6 +6,8 @@ from feincms.extensions.featured import * warnings.warn( - 'Import %(name)s from feincms.extensions.%(name)s' % { - 'name': __name__.split('.')[-1], - }, DeprecationWarning, stacklevel=2) + "Import %(name)s from feincms.extensions.%(name)s" + % {"name": __name__.split(".")[-1]}, + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index 8dc6add93..aa386950f 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -6,6 +6,8 @@ from feincms.extensions.seo import * warnings.warn( - 'Import %(name)s from feincms.extensions.%(name)s' % { - 'name': __name__.split('.')[-1], - }, DeprecationWarning, stacklevel=2) + "Import %(name)s from feincms.extensions.%(name)s" + % {"name": __name__.split(".")[-1]}, + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index 7d8842186..c89c8d538 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -6,6 +6,8 @@ from feincms.extensions.translations import * warnings.warn( - 'Import %(name)s from feincms.extensions.%(name)s' % { - 'name': __name__.split('.')[-1], - }, DeprecationWarning, stacklevel=2) + "Import %(name)s from feincms.extensions.%(name)s" + % {"name": __name__.split(".")[-1]}, + DeprecationWarning, + stacklevel=2, +) diff --git a/feincms/module/medialibrary/__init__.py b/feincms/module/medialibrary/__init__.py index fc7e02a00..98a59597d 100644 --- a/feincms/module/medialibrary/__init__.py +++ b/feincms/module/medialibrary/__init__.py @@ -7,6 +7,6 @@ import logging # ------------------------------------------------------------------------ -logger = logging.getLogger('feincms.medialibrary') +logger = logging.getLogger("feincms.medialibrary") # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/contents.py b/feincms/module/medialibrary/contents.py index b5b2cd435..ada88df68 100644 --- a/feincms/module/medialibrary/contents.py +++ b/feincms/module/medialibrary/contents.py @@ -11,8 +11,8 @@ class MediaFileContentInline(FeinCMSInline): - raw_id_fields = ('mediafile',) - radio_fields = {'type': admin.VERTICAL} + raw_id_fields = ("mediafile",) + radio_fields = {"type": admin.VERTICAL} class MediaFileContent(ContentWithMediaFile): @@ -44,36 +44,35 @@ class MediaFileContent(ContentWithMediaFile): class Meta: abstract = True - verbose_name = _('media file') - verbose_name_plural = _('media files') + verbose_name = _("media file") + verbose_name_plural = _("media files") @classmethod def initialize_type(cls, TYPE_CHOICES=None): if TYPE_CHOICES is None: raise ImproperlyConfigured( - 'You have to set TYPE_CHOICES when' - ' creating a %s' % cls.__name__) + "You have to set TYPE_CHOICES when" " creating a %s" % cls.__name__ + ) cls.add_to_class( - 'type', + "type", models.CharField( - _('type'), + _("type"), max_length=20, choices=TYPE_CHOICES, default=TYPE_CHOICES[0][0], - ) + ), ) def render(self, **kwargs): return ct_render_to_string( [ - 'content/mediafile/%s_%s.html' % ( - self.mediafile.type, self.type), - 'content/mediafile/%s.html' % self.mediafile.type, - 'content/mediafile/%s.html' % self.type, - 'content/mediafile/default.html', + "content/mediafile/%s_%s.html" % (self.mediafile.type, self.type), + "content/mediafile/%s.html" % self.mediafile.type, + "content/mediafile/%s.html" % self.type, + "content/mediafile/default.html", ], - {'content': self}, - request=kwargs.get('request'), - context=kwargs.get('context'), + {"content": self}, + request=kwargs.get("request"), + context=kwargs.get("context"), ) diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 95046060b..c27f8fb41 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -18,7 +18,7 @@ from .thumbnail import admin_thumbnail -__all__ = ('MediaFileForeignKey', 'ContentWithMediaFile') +__all__ = ("MediaFileForeignKey", "ContentWithMediaFile") # ------------------------------------------------------------------------ @@ -29,20 +29,21 @@ def __init__(self, original): def label_for_value(self, value): key = self.rel.get_related_field().name try: - obj = self.rel.to._default_manager.using(self.db).get( - **{key: value}) - label = [' %s' % escape( - shorten_string(six.text_type(obj)))] + obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) + label = [ + " %s" % escape(shorten_string(six.text_type(obj))) + ] image = admin_thumbnail(obj) if image: label.append( '
    ' % image) + "/>" % image + ) - return ''.join(label) + return "".join(label) except (ValueError, self.rel.to.DoesNotExist): - return '' + return "" class MediaFileForeignKey(models.ForeignKey): @@ -53,24 +54,25 @@ class MediaFileForeignKey(models.ForeignKey): """ def __init__(self, *args, **kwargs): - if not args and 'to' not in kwargs: + if not args and "to" not in kwargs: args = (MediaFile,) super(MediaFileForeignKey, self).__init__(*args, **kwargs) def formfield(self, **kwargs): - if 'widget' in kwargs and isinstance( - kwargs['widget'], ForeignKeyRawIdWidget): - kwargs['widget'] = MediaFileForeignKeyRawIdWidget(kwargs['widget']) + if "widget" in kwargs and isinstance(kwargs["widget"], ForeignKeyRawIdWidget): + kwargs["widget"] = MediaFileForeignKeyRawIdWidget(kwargs["widget"]) return super(MediaFileForeignKey, self).formfield(**kwargs) class ContentWithMediaFile(models.Model): class feincms_item_editor_inline(FeinCMSInline): - raw_id_fields = ('mediafile',) + raw_id_fields = ("mediafile",) mediafile = MediaFileForeignKey( - MediaFile, verbose_name=_('media file'), related_name='+', - on_delete=models.PROTECT + MediaFile, + verbose_name=_("media file"), + related_name="+", + on_delete=models.PROTECT, ) class Meta: @@ -83,16 +85,22 @@ class AdminFileWithPreviewWidget(AdminFileWidget): Simple AdminFileWidget, but detects if the file is an image and tries to render a small thumbnail besides the input field. """ + def render(self, name, value, attrs=None, *args, **kwargs): r = super(AdminFileWithPreviewWidget, self).render( - name, value, attrs=attrs, *args, **kwargs) + name, value, attrs=attrs, *args, **kwargs + ) - if value and getattr(value, 'instance', None): + if value and getattr(value, "instance", None): image = admin_thumbnail(value.instance) if image: - r = mark_safe(( - '' % image) + r) + r = mark_safe( + ( + '" % image + ) + + r + ) return r diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index e592bd591..c43e91cc3 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -20,41 +20,43 @@ class MediaCategoryAdminForm(forms.ModelForm): class Meta: model = Category - fields = '__all__' + fields = "__all__" def clean_parent(self): - data = self.cleaned_data['parent'] + data = self.cleaned_data["parent"] if data is not None and self.instance in data.path_list(): - raise forms.ValidationError( - _("This would create a loop in the hierarchy")) + raise forms.ValidationError(_("This would create a loop in the hierarchy")) return data def __init__(self, *args, **kwargs): super(MediaCategoryAdminForm, self).__init__(*args, **kwargs) - self.fields['parent'].queryset =\ - self.fields['parent'].queryset.exclude(pk=self.instance.pk) + self.fields["parent"].queryset = self.fields["parent"].queryset.exclude( + pk=self.instance.pk + ) # ------------------------------------------------------------------------ class MediaFileAdminForm(forms.ModelForm): class Meta: model = MediaFile - widgets = {'file': AdminFileWithPreviewWidget} - fields = '__all__' + widgets = {"file": AdminFileWithPreviewWidget} + fields = "__all__" def __init__(self, *args, **kwargs): super(MediaFileAdminForm, self).__init__(*args, **kwargs) if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: field = self.instance.file.field - if not hasattr(field, '_feincms_generate_filename_patched'): + if not hasattr(field, "_feincms_generate_filename_patched"): original_generate = field.generate_filename def _gen_fname(instance, filename): - if instance.id and hasattr(instance, 'original_name'): - logger.info("Overwriting file %s with new data" % ( - instance.original_name)) + if instance.id and hasattr(instance, "original_name"): + logger.info( + "Overwriting file %s with new data" + % (instance.original_name) + ) instance.file.storage.delete(instance.original_name) return instance.original_name @@ -65,18 +67,21 @@ def _gen_fname(instance, filename): def clean_file(self): if settings.FEINCMS_MEDIAFILE_OVERWRITE and self.instance.id: - new_base, new_ext = os.path.splitext( - self.cleaned_data['file'].name) + new_base, new_ext = os.path.splitext(self.cleaned_data["file"].name) old_base, old_ext = os.path.splitext(self.instance.file.name) if new_ext.lower() != old_ext.lower(): - raise forms.ValidationError(_( - "Cannot overwrite with different file type (attempt to" - " overwrite a %(old_ext)s with a %(new_ext)s)" - ) % {'old_ext': old_ext, 'new_ext': new_ext}) + raise forms.ValidationError( + _( + "Cannot overwrite with different file type (attempt to" + " overwrite a %(old_ext)s with a %(new_ext)s)" + ) + % {"old_ext": old_ext, "new_ext": new_ext} + ) self.instance.original_name = self.instance.file.name - return self.cleaned_data['file'] + return self.cleaned_data["file"] + # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index d52e9fb2c..ae20ae55b 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -19,6 +19,7 @@ from django.utils.safestring import mark_safe from django.utils.translation import ungettext, ugettext_lazy as _ from django.views.decorators.csrf import csrf_protect + try: from django.urls import reverse except ImportError: @@ -37,11 +38,11 @@ # ----------------------------------------------------------------------- class CategoryAdmin(admin.ModelAdmin): form = MediaCategoryAdminForm - list_display = ['path'] - list_filter = ['parent'] + list_display = ["path"] + list_filter = ["parent"] list_per_page = 25 - search_fields = ['title'] - prepopulated_fields = {'slug': ('title',)} + search_fields = ["title"] + prepopulated_fields = {"slug": ("title",)} # ------------------------------------------------------------------------ @@ -51,10 +52,10 @@ class AddCategoryForm(forms.Form): category = forms.ModelChoiceField(Category.objects.all()) form = None - if 'apply' in request.POST: + if "apply" in request.POST: form = AddCategoryForm(request.POST) if form.is_valid(): - category = form.cleaned_data['category'] + category = form.cleaned_data["category"] count = 0 for mediafile in queryset: @@ -62,28 +63,30 @@ class AddCategoryForm(forms.Form): count += 1 message = ungettext( - 'Successfully added %(count)d media file to %(category)s.', - 'Successfully added %(count)d media files to %(category)s.', - count) % {'count': count, 'category': category} + "Successfully added %(count)d media file to %(category)s.", + "Successfully added %(count)d media files to %(category)s.", + count, + ) % {"count": count, "category": category} modeladmin.message_user(request, message) return HttpResponseRedirect(request.get_full_path()) - if 'cancel' in request.POST: + if "cancel" in request.POST: return HttpResponseRedirect(request.get_full_path()) if not form: - form = AddCategoryForm(initial={ - '_selected_action': request.POST.getlist( - admin.ACTION_CHECKBOX_NAME), - }) + form = AddCategoryForm( + initial={ + "_selected_action": request.POST.getlist(admin.ACTION_CHECKBOX_NAME) + } + ) - return render(request, 'admin/medialibrary/add_to_category.html', { - 'mediafiles': queryset, - 'category_form': form, - 'opts': modeladmin.model._meta, - }) + return render( + request, + "admin/medialibrary/add_to_category.html", + {"mediafiles": queryset, "category_form": form, "opts": modeladmin.model._meta}, + ) -assign_category.short_description = _('Add selected media files to category') +assign_category.short_description = _("Add selected media files to category") # ------------------------------------------------------------------------- @@ -98,12 +101,10 @@ def save_as_zipfile(modeladmin, request, queryset): messages.error(request, _("ZIP file export failed: %s") % str(e)) return - return HttpResponseRedirect( - os.path.join(django_settings.MEDIA_URL, zip_name)) + return HttpResponseRedirect(os.path.join(django_settings.MEDIA_URL, zip_name)) -save_as_zipfile.short_description = _( - 'Export selected media files as zip file') +save_as_zipfile.short_description = _("Export selected media files as zip file") # ------------------------------------------------------------------------ @@ -111,14 +112,13 @@ class MediaFileAdmin(ExtensionModelAdmin): form = MediaFileAdminForm save_on_top = True - date_hierarchy = 'created' + date_hierarchy = "created" inlines = [admin_translationinline(MediaFileTranslation)] - list_display = [ - 'admin_thumbnail', '__str__', 'file_info', 'formatted_created'] - list_display_links = ['__str__'] - list_filter = ['type', 'categories'] + list_display = ["admin_thumbnail", "__str__", "file_info", "formatted_created"] + list_display_links = ["__str__"] + list_filter = ["type", "categories"] list_per_page = 25 - search_fields = ['copyright', 'file', 'translations__caption'] + search_fields = ["copyright", "file", "translations__caption"] filter_horizontal = ("categories",) actions = [assign_category, save_as_zipfile] @@ -127,46 +127,50 @@ def get_urls(self): return [ url( - r'^mediafile-bulk-upload/$', + r"^mediafile-bulk-upload/$", self.admin_site.admin_view(MediaFileAdmin.bulk_upload), {}, - name='mediafile_bulk_upload', - ), + name="mediafile_bulk_upload", + ) ] + super(MediaFileAdmin, self).get_urls() def changelist_view(self, request, extra_context=None): if extra_context is None: extra_context = {} - extra_context['categories'] = Category.objects.order_by('title') + extra_context["categories"] = Category.objects.order_by("title") return super(MediaFileAdmin, self).changelist_view( - request, extra_context=extra_context) + request, extra_context=extra_context + ) def admin_thumbnail(self, obj): image = admin_thumbnail(obj) if image: - return mark_safe(""" + return mark_safe( + """ - """ % { - 'url': obj.file.url, - 'image': image} + """ + % {"url": obj.file.url, "image": image} ) - return '' - admin_thumbnail.short_description = _('Preview') + return "" + + admin_thumbnail.short_description = _("Preview") def formatted_file_size(self, obj): return filesizeformat(obj.file_size) + formatted_file_size.short_description = _("file size") - formatted_file_size.admin_order_field = 'file_size' + formatted_file_size.admin_order_field = "file_size" def formatted_created(self, obj): return obj.created.strftime("%Y-%m-%d") + formatted_created.short_description = _("created") - formatted_created.admin_order_field = 'created' + formatted_created.admin_order_field = "created" def file_type(self, obj): t = obj.filetypes_dict[obj.type] - if obj.type == 'image': + if obj.type == "image": # get_image_dimensions is expensive / slow if the storage is not # local filesystem (indicated by availability the path property) try: @@ -180,8 +184,9 @@ def file_type(self, obj): except (IOError, TypeError, ValueError) as e: t += " (%s)" % e return mark_safe(t) - file_type.admin_order_field = 'type' - file_type.short_description = _('file type') + + file_type.admin_order_field = "type" + file_type.short_description = _("file type") def file_info(self, obj): """ @@ -191,47 +196,54 @@ def file_info(self, obj): the file name later on, this can be used to access the file name from JS, like for example a TinyMCE connector shim. """ - return mark_safe(( - '' - ' %s
    %s, %s' - ) % ( - obj.id, - obj.file.name, - obj.id, - shorten_string(os.path.basename(obj.file.name), max_length=40), - self.file_type(obj), - self.formatted_file_size(obj), - )) - file_info.admin_order_field = 'file' - file_info.short_description = _('file info') + return mark_safe( + ( + '' + " %s
    %s, %s" + ) + % ( + obj.id, + obj.file.name, + obj.id, + shorten_string(os.path.basename(obj.file.name), max_length=40), + self.file_type(obj), + self.formatted_file_size(obj), + ) + ) + + file_info.admin_order_field = "file" + file_info.short_description = _("file info") @staticmethod @csrf_protect - @permission_required('medialibrary.add_mediafile') + @permission_required("medialibrary.add_mediafile") def bulk_upload(request): - if request.method == 'POST' and 'data' in request.FILES: + if request.method == "POST" and "data" in request.FILES: try: count = import_zipfile( - request.POST.get('category'), - request.POST.get('overwrite', False), - request.FILES['data']) + request.POST.get("category"), + request.POST.get("overwrite", False), + request.FILES["data"], + ) messages.info(request, _("%d files imported") % count) except Exception as e: messages.error(request, _("ZIP import failed: %s") % e) else: messages.error(request, _("No input file given")) - return HttpResponseRedirect( - reverse('admin:medialibrary_mediafile_changelist')) + return HttpResponseRedirect(reverse("admin:medialibrary_mediafile_changelist")) def get_queryset(self, request): - return super(MediaFileAdmin, self).get_queryset(request).transform( - lookup_translations()) + return ( + super(MediaFileAdmin, self) + .get_queryset(request) + .transform(lookup_translations()) + ) def save_model(self, request, obj, form, change): obj.purge_translation_cache() - return super(MediaFileAdmin, self).save_model( - request, obj, form, change) + return super(MediaFileAdmin, self).save_model(request, obj, form, change) + # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 66fd1d069..424abd327 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -18,7 +18,10 @@ from feincms import settings from feincms.models import ExtensionsMixin from feincms.translations import ( - TranslatedObjectMixin, Translation, TranslatedObjectManager) + TranslatedObjectMixin, + Translation, + TranslatedObjectManager, +) from . import logger @@ -29,9 +32,9 @@ class CategoryManager(models.Manager): Simple manager which exists only to supply ``.select_related("parent")`` on querysets since we can't even __str__ efficiently without it. """ + def get_queryset(self): - return super(CategoryManager, self).get_queryset().select_related( - "parent") + return super(CategoryManager, self).get_queryset().select_related("parent") # ------------------------------------------------------------------------ @@ -42,26 +45,30 @@ class Category(models.Model): library. """ - title = models.CharField(_('title'), max_length=200) + title = models.CharField(_("title"), max_length=200) parent = models.ForeignKey( - 'self', blank=True, null=True, + "self", + blank=True, + null=True, on_delete=models.CASCADE, - related_name='children', limit_choices_to={'parent__isnull': True}, - verbose_name=_('parent')) + related_name="children", + limit_choices_to={"parent__isnull": True}, + verbose_name=_("parent"), + ) - slug = models.SlugField(_('slug'), max_length=150) + slug = models.SlugField(_("slug"), max_length=150) class Meta: - ordering = ['parent__title', 'title'] - verbose_name = _('category') - verbose_name_plural = _('categories') - app_label = 'medialibrary' + ordering = ["parent__title", "title"] + verbose_name = _("category") + verbose_name_plural = _("categories") + app_label = "medialibrary" objects = CategoryManager() def __str__(self): if self.parent_id: - return '%s - %s' % (self.parent.title, self.title) + return "%s - %s" % (self.parent.title, self.title) return self.title @@ -70,6 +77,7 @@ def save(self, *args, **kwargs): self.slug = slugify(self.title) super(Category, self).save(*args, **kwargs) + save.alters_data = True def path_list(self): @@ -80,7 +88,7 @@ def path_list(self): return p def path(self): - return ' - '.join((f.title for f in self.path_list())) + return " - ".join((f.title for f in self.path_list())) # ------------------------------------------------------------------------ @@ -93,26 +101,25 @@ class MediaFileBase(models.Model, ExtensionsMixin, TranslatedObjectMixin): """ file = models.FileField( - _('file'), max_length=255, - upload_to=settings.FEINCMS_MEDIALIBRARY_UPLOAD_TO) - type = models.CharField( - _('file type'), max_length=12, editable=False, - choices=()) - created = models.DateTimeField( - _('created'), editable=False, default=timezone.now) - copyright = models.CharField(_('copyright'), max_length=200, blank=True) + _("file"), max_length=255, upload_to=settings.FEINCMS_MEDIALIBRARY_UPLOAD_TO + ) + type = models.CharField(_("file type"), max_length=12, editable=False, choices=()) + created = models.DateTimeField(_("created"), editable=False, default=timezone.now) + copyright = models.CharField(_("copyright"), max_length=200, blank=True) file_size = models.IntegerField( - _("file size"), blank=True, null=True, editable=False) + _("file size"), blank=True, null=True, editable=False + ) categories = models.ManyToManyField( - Category, verbose_name=_('categories'), blank=True) + Category, verbose_name=_("categories"), blank=True + ) categories.category_filter = True class Meta: abstract = True - ordering = ['-created'] - verbose_name = _('media file') - verbose_name_plural = _('media files') + ordering = ["-created"] + verbose_name = _("media file") + verbose_name_plural = _("media files") objects = TranslatedObjectManager() @@ -121,7 +128,7 @@ class Meta: @classmethod def reconfigure(cls, upload_to=None, storage=None): - f = cls._meta.get_field('file') + f = cls._meta.get_field("file") # Ugh. Copied relevant parts from django/db/models/fields/files.py # FileField.__init__ (around line 225) if storage: @@ -136,7 +143,7 @@ def register_filetypes(cls, *types): cls.filetypes[0:0] = types choices = [t[0:2] for t in cls.filetypes] cls.filetypes_dict = dict(choices) - cls._meta.get_field('type').choices[:] = choices + cls._meta.get_field("type").choices[:] = choices def __init__(self, *args, **kwargs): super(MediaFileBase, self).__init__(*args, **kwargs) @@ -154,7 +161,7 @@ def __str__(self): pass if trans: - trans = '%s' % trans + trans = "%s" % trans if trans.strip(): return trans return os.path.basename(self.file.name) @@ -194,16 +201,19 @@ def save(self, *args, **kwargs): super(MediaFileBase, self).save(*args, **kwargs) - logger.info("Saved mediafile %d (%s, type %s, %d bytes)" % ( - self.id, self.file.name, self.type, self.file_size or 0)) + logger.info( + "Saved mediafile %d (%s, type %s, %d bytes)" + % (self.id, self.file.name, self.type, self.file_size or 0) + ) # User uploaded a new file. Try to get rid of the old file in # storage, to avoid having orphaned files hanging around. - if getattr(self, '_original_file_name', None): + if getattr(self, "_original_file_name", None): if self.file.name != self._original_file_name: self.delete_mediafile(self._original_file_name) self.purge_translation_cache() + save.alters_data = True def delete_mediafile(self, name=None): @@ -218,39 +228,61 @@ def delete_mediafile(self, name=None): # ------------------------------------------------------------------------ MediaFileBase.register_filetypes( # Should we be using imghdr.what instead of extension guessing? - ('image', _('Image'), lambda f: re.compile( - r'\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$', re.IGNORECASE).search(f)), - ('video', _('Video'), lambda f: re.compile( - r'\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv|flv)$', - re.IGNORECASE).search(f)), - ('audio', _('Audio'), lambda f: re.compile( - r'\.(au|mp3|m4a|wma|oga|ram|wav)$', re.IGNORECASE).search(f)), - ('pdf', _('PDF document'), lambda f: f.lower().endswith('.pdf')), - ('swf', _('Flash'), lambda f: f.lower().endswith('.swf')), - ('txt', _('Text'), lambda f: f.lower().endswith('.txt')), - ('rtf', _('Rich Text'), lambda f: f.lower().endswith('.rtf')), - ('zip', _('Zip archive'), lambda f: f.lower().endswith('.zip')), - ('doc', _('Microsoft Word'), lambda f: re.compile( - r'\.docx?$', re.IGNORECASE).search(f)), - ('xls', _('Microsoft Excel'), lambda f: re.compile( - r'\.xlsx?$', re.IGNORECASE).search(f)), - ('ppt', _('Microsoft PowerPoint'), lambda f: re.compile( - r'\.pptx?$', re.IGNORECASE).search(f)), - ('other', _('Binary'), lambda f: True), # Must be last + ( + "image", + _("Image"), + lambda f: re.compile( + r"\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$", re.IGNORECASE + ).search(f), + ), + ( + "video", + _("Video"), + lambda f: re.compile( + r"\.(mov|m[14]v|mp4|avi|mpe?g|qt|ogv|wmv|flv)$", re.IGNORECASE + ).search(f), + ), + ( + "audio", + _("Audio"), + lambda f: re.compile(r"\.(au|mp3|m4a|wma|oga|ram|wav)$", re.IGNORECASE).search( + f + ), + ), + ("pdf", _("PDF document"), lambda f: f.lower().endswith(".pdf")), + ("swf", _("Flash"), lambda f: f.lower().endswith(".swf")), + ("txt", _("Text"), lambda f: f.lower().endswith(".txt")), + ("rtf", _("Rich Text"), lambda f: f.lower().endswith(".rtf")), + ("zip", _("Zip archive"), lambda f: f.lower().endswith(".zip")), + ( + "doc", + _("Microsoft Word"), + lambda f: re.compile(r"\.docx?$", re.IGNORECASE).search(f), + ), + ( + "xls", + _("Microsoft Excel"), + lambda f: re.compile(r"\.xlsx?$", re.IGNORECASE).search(f), + ), + ( + "ppt", + _("Microsoft PowerPoint"), + lambda f: re.compile(r"\.pptx?$", re.IGNORECASE).search(f), + ), + ("other", _("Binary"), lambda f: True), # Must be last ) # ------------------------------------------------------------------------ class MediaFile(MediaFileBase): class Meta: - app_label = 'medialibrary' + app_label = "medialibrary" @receiver(post_delete, sender=MediaFile) def _mediafile_post_delete(sender, instance, **kwargs): instance.delete_mediafile() - logger.info("Deleted mediafile %d (%s)" % ( - instance.id, instance.file.name)) + logger.info("Deleted mediafile %d (%s)" % (instance.id, instance.file.name)) # ------------------------------------------------------------------------ @@ -260,14 +292,14 @@ class MediaFileTranslation(Translation(MediaFile)): Translated media file caption and description. """ - caption = models.CharField(_('caption'), max_length=1000) - description = models.TextField(_('description'), blank=True) + caption = models.CharField(_("caption"), max_length=1000) + description = models.TextField(_("description"), blank=True) class Meta: - verbose_name = _('media file translation') - verbose_name_plural = _('media file translations') - unique_together = ('parent', 'language_code') - app_label = 'medialibrary' + verbose_name = _("media file translation") + verbose_name_plural = _("media file translations") + unique_together = ("parent", "language_code") + app_label = "medialibrary" def __str__(self): return self.caption diff --git a/feincms/module/medialibrary/thumbnail.py b/feincms/module/medialibrary/thumbnail.py index a70c2dc27..5dce9cce9 100644 --- a/feincms/module/medialibrary/thumbnail.py +++ b/feincms/module/medialibrary/thumbnail.py @@ -5,8 +5,8 @@ from feincms.utils import get_object -def default_admin_thumbnail(mediafile, dimensions='100x100', **kwargs): - if mediafile.type != 'image': +def default_admin_thumbnail(mediafile, dimensions="100x100", **kwargs): + if mediafile.type != "image": return None return feincms_thumbnail.thumbnail(mediafile.file, dimensions) @@ -15,9 +15,8 @@ def default_admin_thumbnail(mediafile, dimensions='100x100', **kwargs): _cached_thumbnailer = None -def admin_thumbnail(mediafile, dimensions='100x100'): +def admin_thumbnail(mediafile, dimensions="100x100"): global _cached_thumbnailer if not _cached_thumbnailer: - _cached_thumbnailer = get_object( - settings.FEINCMS_MEDIALIBRARY_THUMBNAIL) + _cached_thumbnailer = get_object(settings.FEINCMS_MEDIALIBRARY_THUMBNAIL) return _cached_thumbnailer(mediafile, dimensions=dimensions) diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 557e82566..2e91376f6 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -23,7 +23,7 @@ # ------------------------------------------------------------------------ -export_magic = 'feincms-export-01' +export_magic = "feincms-export-01" # ------------------------------------------------------------------------ @@ -47,7 +47,7 @@ def import_zipfile(category_id, overwrite, data): info = {} try: info = json.loads(z.comment) - if info['export_magic'] == export_magic: + if info["export_magic"] == export_magic: is_export_file = True except Exception: pass @@ -57,21 +57,21 @@ def import_zipfile(category_id, overwrite, data): category_id_map = {} if is_export_file: for cat in sorted( - info.get('categories', []), - key=lambda k: k.get('level', 999)): + info.get("categories", []), key=lambda k: k.get("level", 999) + ): new_cat, created = Category.objects.get_or_create( - slug=cat['slug'], - title=cat['title']) - category_id_map[cat['id']] = new_cat - if created and cat.get('parent', 0): - parent_cat = category_id_map.get(cat.get('parent', 0), None) + slug=cat["slug"], title=cat["title"] + ) + category_id_map[cat["id"]] = new_cat + if created and cat.get("parent", 0): + parent_cat = category_id_map.get(cat.get("parent", 0), None) if parent_cat: new_cat.parent = parent_cat new_cat.save() count = 0 for zi in z.infolist(): - if not zi.filename.endswith('/'): + if not zi.filename.endswith("/"): bname = os.path.basename(zi.filename) if bname and not bname.startswith(".") and "." in bname: fname, ext = os.path.splitext(bname) @@ -95,36 +95,34 @@ def import_zipfile(category_id, overwrite, data): mf = MediaFile() if overwrite: mf.file.field.upload_to = wanted_dir - mf.copyright = info.get('copyright', '') - mf.file.save( - target_fname, - ContentFile(z.read(zi.filename)), - save=False) + mf.copyright = info.get("copyright", "") + mf.file.save(target_fname, ContentFile(z.read(zi.filename)), save=False) mf.save() found_metadata = False if is_export_file: try: - for tr in info['translations']: + for tr in info["translations"]: found_metadata = True - mt, mt_created =\ - MediaFileTranslation.objects.get_or_create( - parent=mf, language_code=tr['lang']) - mt.caption = tr['caption'] - mt.description = tr.get('description', None) + mt, mt_created = MediaFileTranslation.objects.get_or_create( + parent=mf, language_code=tr["lang"] + ) + mt.caption = tr["caption"] + mt.description = tr.get("description", None) mt.save() # Add categories mf.categories = ( category_id_map[cat_id] - for cat_id in info.get('categories', [])) + for cat_id in info.get("categories", []) + ) except Exception: pass if not found_metadata: mt = MediaFileTranslation() mt.parent = mf - mt.caption = fname.replace('_', ' ') + mt.caption = fname.replace("_", " ") mt.save() if category: @@ -139,10 +137,14 @@ def import_zipfile(category_id, overwrite, data): def export_zipfile(site, queryset): now = timezone.now() zip_name = "export_%s_%04d%02d%02d.zip" % ( - slugify(site.domain), now.year, now.month, now.day) + slugify(site.domain), + now.year, + now.month, + now.day, + ) zip_data = open(os.path.join(django_settings.MEDIA_ROOT, zip_name), "w") - zip_file = zipfile.ZipFile(zip_data, 'w', allowZip64=True) + zip_file = zipfile.ZipFile(zip_data, "w", allowZip64=True) # Save the used categories in the zip file's global comment used_categories = set() @@ -151,28 +153,36 @@ def export_zipfile(site, queryset): used_categories.update(cat.path_list()) info = { - 'export_magic': export_magic, - 'categories': [{ - 'id': cat.id, - 'title': cat.title, - 'slug': cat.slug, - 'parent': cat.parent_id or 0, - 'level': len(cat.path_list()), - } for cat in used_categories], + "export_magic": export_magic, + "categories": [ + { + "id": cat.id, + "title": cat.title, + "slug": cat.slug, + "parent": cat.parent_id or 0, + "level": len(cat.path_list()), + } + for cat in used_categories + ], } zip_file.comment = json.dumps(info) for mf in queryset: ctime = time.localtime(os.stat(mf.file.path).st_ctime) - info = json.dumps({ - 'copyright': mf.copyright, - 'categories': [cat.id for cat in mf.categories.all()], - 'translations': [{ - 'lang': t.language_code, - 'caption': t.caption, - 'description': t.description, - } for t in mf.translations.all()], - }) + info = json.dumps( + { + "copyright": mf.copyright, + "categories": [cat.id for cat in mf.categories.all()], + "translations": [ + { + "lang": t.language_code, + "caption": t.caption, + "description": t.description, + } + for t in mf.translations.all() + ], + } + ) with open(mf.file.path, "r") as file_data: zip_info = zipfile.ZipInfo( @@ -183,10 +193,13 @@ def export_zipfile(site, queryset): ctime.tm_mday, ctime.tm_hour, ctime.tm_min, - ctime.tm_sec)) + ctime.tm_sec, + ), + ) zip_info.comment = info zip_file.writestr(zip_info, file_data.read()) return zip_name + # ------------------------------------------------------------------------ diff --git a/feincms/module/mixins.py b/feincms/module/mixins.py index ed873334d..56f2d33b5 100644 --- a/feincms/module/mixins.py +++ b/feincms/module/mixins.py @@ -79,7 +79,7 @@ class ContentObjectMixin(TemplateResponseMixin): context_object_name = None def handler(self, request, *args, **kwargs): - if not hasattr(self.request, '_feincms_extra_context'): + if not hasattr(self.request, "_feincms_extra_context"): self.request._feincms_extra_context = {} r = self.run_request_processors() @@ -121,7 +121,7 @@ def get_template_names(self): def get_context_data(self, **kwargs): context = self.request._feincms_extra_context - context[self.context_object_name or 'feincms_object'] = self.object + context[self.context_object_name or "feincms_object"] = self.object context.update(kwargs) return super(ContentObjectMixin, self).get_context_data(**context) @@ -140,7 +140,7 @@ def run_request_processors(self): also return a ``HttpResponse`` for shortcutting the rendering and returning that response immediately to the client. """ - if not getattr(self.object, 'request_processors', None): + if not getattr(self.object, "request_processors", None): return for fn in reversed(list(self.object.request_processors.values())): @@ -154,7 +154,7 @@ def run_response_processors(self, response): processors are called to modify the response, eg. for setting cache or expiration headers, keeping statistics, etc. """ - if not getattr(self.object, 'response_processors', None): + if not getattr(self.object, "response_processors", None): return for fn in self.object.response_processors.values(): @@ -172,8 +172,9 @@ def process_content_types(self): # did any content type successfully end processing? successful = False - for content in self.object.content.all_of_type(tuple( - self.object._feincms_content_types_with_process)): + for content in self.object.content.all_of_type( + tuple(self.object._feincms_content_types_with_process) + ): try: r = content.process(self.request, view=self) @@ -191,15 +192,17 @@ def process_content_types(self): extra_context = self.request._feincms_extra_context - if (not settings.FEINCMS_ALLOW_EXTRA_PATH and - extra_context.get('extra_path', '/') != '/' and - # XXX Already inside application content. I'm not sure - # whether this fix is really correct... - not extra_context.get('app_config')): - raise Http404(str('Not found (extra_path %r on %r)') % ( - extra_context.get('extra_path', '/'), - self.object, - )) + if ( + not settings.FEINCMS_ALLOW_EXTRA_PATH + and extra_context.get("extra_path", "/") != "/" + # XXX Already inside application content. I'm not sure + # whether this fix is really correct... + and not extra_context.get("app_config") + ): + raise Http404( + str("Not found (extra_path %r on %r)") + % (extra_context.get("extra_path", "/"), self.object) + ) def finalize_content_types(self, response): """ @@ -207,8 +210,9 @@ def finalize_content_types(self, response): returns the final response. """ - for content in self.object.content.all_of_type(tuple( - self.object._feincms_content_types_with_finalize)): + for content in self.object.content.all_of_type( + tuple(self.object._feincms_content_types_with_finalize) + ): r = content.finalize(self.request, response) if r: diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index 4abea4668..1fde24864 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -17,7 +17,7 @@ if settings.FEINCMS_USE_PAGE_ADMIN: ensure_completely_loaded() try: - Page._meta.get_field('template_key') + Page._meta.get_field("template_key") except FieldDoesNotExist: raise ImproperlyConfigured( "The page module requires a 'Page.register_templates()' call " diff --git a/feincms/module/page/extensions/excerpt.py b/feincms/module/page/extensions/excerpt.py index 25fe9004a..6eb0c583d 100644 --- a/feincms/module/page/extensions/excerpt.py +++ b/feincms/module/page/extensions/excerpt.py @@ -13,16 +13,17 @@ class Extension(extensions.Extension): def handle_model(self): self.model.add_to_class( - 'excerpt', + "excerpt", models.TextField( - _('excerpt'), + _("excerpt"), blank=True, help_text=_( - 'Add a brief excerpt summarizing the content' - ' of this page.'))) + "Add a brief excerpt summarizing the content" " of this page." + ), + ), + ) def handle_modeladmin(self, modeladmin): - modeladmin.add_extension_options(_('Excerpt'), { - 'fields': ('excerpt',), - 'classes': ('collapse',), - }) + modeladmin.add_extension_options( + _("Excerpt"), {"fields": ("excerpt",), "classes": ("collapse",)} + ) diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index f44e8f22b..d1564fcca 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -30,7 +30,7 @@ class TypeRegistryMetaClass(type): """ def __init__(cls, name, bases, attrs): - if not hasattr(cls, 'types'): + if not hasattr(cls, "types"): cls.types = [] else: cls.types.append(cls) @@ -46,11 +46,12 @@ class PagePretender(object): parameters on creation: title, url, level. If using the translation extension, also add language. """ + pk = None # emulate mptt properties to get the template tags working class _mptt_meta: - level_attr = 'level' + level_attr = "level" def __init__(self, **kwargs): for k, v in kwargs.items(): @@ -86,7 +87,7 @@ class NavigationExtension(six.with_metaclass(TypeRegistryMetaClass)): The name attribute is shown to the website administrator. """ - name = _('navigation extension') + name = _("navigation extension") def children(self, page, **kwargs): """ @@ -103,51 +104,56 @@ def children(self, page, **kwargs): def navigation_extension_choices(): for ext in NavigationExtension.types: - if (issubclass(ext, NavigationExtension) and - ext is not NavigationExtension): - yield ('%s.%s' % (ext.__module__, ext.__name__), ext.name) + if issubclass(ext, NavigationExtension) and ext is not NavigationExtension: + yield ("%s.%s" % (ext.__module__, ext.__name__), ext.name) def get_extension_class(extension): extension = get_object(extension) if isinstance(extension, types.ModuleType): - return getattr(extension, 'Extension') + return getattr(extension, "Extension") return extension class Extension(extensions.Extension): - ident = 'navigation' # TODO actually use this + ident = "navigation" # TODO actually use this navigation_extensions = None @cached_property def _extensions(self): if self.navigation_extensions is None: return OrderedDict( - ('%s.%s' % (ext.__module__, ext.__name__), ext) + ("%s.%s" % (ext.__module__, ext.__name__), ext) for ext in NavigationExtension.types if ( - issubclass(ext, NavigationExtension) and - ext is not NavigationExtension)) + issubclass(ext, NavigationExtension) + and ext is not NavigationExtension + ) + ) else: return OrderedDict( - ('%s.%s' % (ext.__module__, ext.__name__), ext) - for ext - in map(get_extension_class, self.navigation_extensions)) + ("%s.%s" % (ext.__module__, ext.__name__), ext) + for ext in map(get_extension_class, self.navigation_extensions) + ) def handle_model(self): - choices = [ - (path, ext.name) for path, ext in self._extensions.items()] + choices = [(path, ext.name) for path, ext in self._extensions.items()] self.model.add_to_class( - 'navigation_extension', + "navigation_extension", models.CharField( - _('navigation extension'), + _("navigation extension"), choices=choices, - blank=True, null=True, max_length=200, + blank=True, + null=True, + max_length=200, help_text=_( - 'Select the module providing subpages for this page if' - ' you need to customize the navigation.'))) + "Select the module providing subpages for this page if" + " you need to customize the navigation." + ), + ), + ) extension = self @@ -169,7 +175,7 @@ def extended_navigation(self, **kwargs): return self.children.in_navigation() def handle_modeladmin(self, modeladmin): - modeladmin.add_extension_options(_('Navigation extension'), { - 'fields': ('navigation_extension',), - 'classes': ('collapse',), - }) + modeladmin.add_extension_options( + _("Navigation extension"), + {"fields": ("navigation_extension",), "classes": ("collapse",)}, + ) diff --git a/feincms/module/page/extensions/navigationgroups.py b/feincms/module/page/extensions/navigationgroups.py index fc47ec033..eef662295 100644 --- a/feincms/module/page/extensions/navigationgroups.py +++ b/feincms/module/page/extensions/navigationgroups.py @@ -12,24 +12,23 @@ class Extension(extensions.Extension): - ident = 'navigationgroups' - groups = [ - ('default', _('Default')), - ('footer', _('Footer')), - ] + ident = "navigationgroups" + groups = [("default", _("Default")), ("footer", _("Footer"))] def handle_model(self): self.model.add_to_class( - 'navigation_group', + "navigation_group", models.CharField( - _('navigation group'), + _("navigation group"), choices=self.groups, default=self.groups[0][0], max_length=20, blank=True, - db_index=True)) + db_index=True, + ), + ) def handle_modeladmin(self, modeladmin): - modeladmin.add_extension_options('navigation_group') - modeladmin.extend_list('list_display', ['navigation_group']) - modeladmin.extend_list('list_filter', ['navigation_group']) + modeladmin.add_extension_options("navigation_group") + modeladmin.extend_list("list_display", ["navigation_group"]) + modeladmin.extend_list("list_filter", ["navigation_group"]) diff --git a/feincms/module/page/extensions/relatedpages.py b/feincms/module/page/extensions/relatedpages.py index 2ddfb0ef7..2a5cf02d7 100644 --- a/feincms/module/page/extensions/relatedpages.py +++ b/feincms/module/page/extensions/relatedpages.py @@ -12,17 +12,19 @@ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('related_pages', models.ManyToManyField( - settings.FEINCMS_DEFAULT_PAGE_MODEL, - blank=True, - related_name='%(app_label)s_%(class)s_related', - help_text=_( - 'Select pages that should be listed as related content.'))) + self.model.add_to_class( + "related_pages", + models.ManyToManyField( + settings.FEINCMS_DEFAULT_PAGE_MODEL, + blank=True, + related_name="%(app_label)s_%(class)s_related", + help_text=_("Select pages that should be listed as related content."), + ), + ) def handle_modeladmin(self, modeladmin): - modeladmin.extend_list('filter_horizontal', ['related_pages']) + modeladmin.extend_list("filter_horizontal", ["related_pages"]) - modeladmin.add_extension_options(_('Related pages'), { - 'fields': ('related_pages',), - 'classes': ('collapse',), - }) + modeladmin.add_extension_options( + _("Related pages"), {"fields": ("related_pages",), "classes": ("collapse",)} + ) diff --git a/feincms/module/page/extensions/sites.py b/feincms/module/page/extensions/sites.py index b0b25d245..69ad32cd9 100644 --- a/feincms/module/page/extensions/sites.py +++ b/feincms/module/page/extensions/sites.py @@ -16,14 +16,18 @@ def current_site(queryset): class Extension(extensions.Extension): def handle_model(self): self.model.add_to_class( - 'site', + "site", models.ForeignKey( - Site, verbose_name=_('Site'), default=settings.SITE_ID, - on_delete=models.CASCADE)) + Site, + verbose_name=_("Site"), + default=settings.SITE_ID, + on_delete=models.CASCADE, + ), + ) - PageManager.add_to_active_filters(current_site, key='current_site') + PageManager.add_to_active_filters(current_site, key="current_site") def handle_modeladmin(self, modeladmin): - modeladmin.extend_list('list_display', ['site']) - modeladmin.extend_list('list_filter', ['site']) - modeladmin.add_extension_options('site') + modeladmin.extend_list("list_display", ["site"]) + modeladmin.extend_list("list_filter", ["site"]) + modeladmin.add_extension_options("site") diff --git a/feincms/module/page/extensions/symlinks.py b/feincms/module/page/extensions/symlinks.py index c5e4c095b..549d03342 100644 --- a/feincms/module/page/extensions/symlinks.py +++ b/feincms/module/page/extensions/symlinks.py @@ -14,26 +14,29 @@ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('symlinked_page', models.ForeignKey( - 'self', - blank=True, - null=True, - on_delete=models.CASCADE, - related_name='%(app_label)s_%(class)s_symlinks', - verbose_name=_('symlinked page'), - help_text=_('All content is inherited from this page if given.'))) + self.model.add_to_class( + "symlinked_page", + models.ForeignKey( + "self", + blank=True, + null=True, + on_delete=models.CASCADE, + related_name="%(app_label)s_%(class)s_symlinks", + verbose_name=_("symlinked page"), + help_text=_("All content is inherited from this page if given."), + ), + ) @monkeypatch_property(self.model) def content(self): - if not hasattr(self, '_content_proxy'): + if not hasattr(self, "_content_proxy"): if self.symlinked_page: - self._content_proxy = self.content_proxy_class( - self.symlinked_page) + self._content_proxy = self.content_proxy_class(self.symlinked_page) else: self._content_proxy = self.content_proxy_class(self) return self._content_proxy def handle_modeladmin(self, modeladmin): - modeladmin.extend_list('raw_id_fields', ['symlinked_page']) - modeladmin.add_extension_options('symlinked_page') + modeladmin.extend_list("raw_id_fields", ["symlinked_page"]) + modeladmin.add_extension_options("symlinked_page") diff --git a/feincms/module/page/extensions/titles.py b/feincms/module/page/extensions/titles.py index 68529b113..d70da3c43 100644 --- a/feincms/module/page/extensions/titles.py +++ b/feincms/module/page/extensions/titles.py @@ -15,20 +15,30 @@ class Extension(extensions.Extension): def handle_model(self): - self.model.add_to_class('_content_title', models.TextField( - _('content title'), - blank=True, - help_text=_( - 'The first line is the main title, the following' - ' lines are subtitles.'))) - - self.model.add_to_class('_page_title', models.CharField( - _('page title'), - max_length=69, - blank=True, - help_text=_( - 'Page title for browser window. Same as title by' - ' default. Must be 69 characters or fewer.'))) + self.model.add_to_class( + "_content_title", + models.TextField( + _("content title"), + blank=True, + help_text=_( + "The first line is the main title, the following" + " lines are subtitles." + ), + ), + ) + + self.model.add_to_class( + "_page_title", + models.CharField( + _("page title"), + max_length=69, + blank=True, + help_text=_( + "Page title for browser window. Same as title by" + " default. Must be 69 characters or fewer." + ), + ), + ) @monkeypatch_property(self.model) def page_title(self): @@ -54,10 +64,10 @@ def content_title(self): @monkeypatch_property(self.model) def content_subtitle(self): - return '\n'.join(self._content_title.splitlines()[1:]) + return "\n".join(self._content_title.splitlines()[1:]) def handle_modeladmin(self, modeladmin): - modeladmin.add_extension_options(_('Titles'), { - 'fields': ('_content_title', '_page_title'), - 'classes': ('collapse',), - }) + modeladmin.add_extension_options( + _("Titles"), + {"fields": ("_content_title", "_page_title"), "classes": ("collapse",)}, + ) diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 1e7f3abd8..9d115b503 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -21,28 +21,38 @@ class RedirectToWidget(ForeignKeyRawIdWidget): def label_for_value(self, value): match = re.match( # XXX this regex would be available as .models.REDIRECT_TO_RE - r'^(?P\w+).(?P\w+):(?P\d+)$', - value) + r"^(?P\w+).(?P\w+):(?P\d+)$", + value, + ) if match: matches = match.groupdict() - model = apps.get_model(matches['app_label'], matches['model_name']) + model = apps.get_model(matches["app_label"], matches["model_name"]) try: - instance = model._default_manager.get(pk=int(matches['pk'])) - return ' %s (%s)' % ( - instance, instance.get_absolute_url()) + instance = model._default_manager.get(pk=int(matches["pk"])) + return " %s (%s)" % ( + instance, + instance.get_absolute_url(), + ) except model.DoesNotExist: pass - return '' + return "" # ------------------------------------------------------------------------ class PageAdminForm(MPTTAdminForm): never_copy_fields = ( - 'title', 'slug', 'parent', 'active', 'override_url', - 'translation_of', '_content_title', '_page_title') + "title", + "slug", + "parent", + "active", + "override_url", + "translation_of", + "_content_title", + "_page_title", + ) @property def page_model(self): @@ -55,12 +65,11 @@ def page_manager(self): def __init__(self, *args, **kwargs): ensure_completely_loaded() - if 'initial' in kwargs: - if 'parent' in kwargs['initial']: + if "initial" in kwargs: + if "parent" in kwargs["initial"]: # Prefill a few form values from the parent page try: - page = self.page_manager.get( - pk=kwargs['initial']['parent']) + page = self.page_manager.get(pk=kwargs["initial"]["parent"]) data = model_to_dict(page) @@ -73,76 +82,80 @@ def __init__(self, *args, **kwargs): if field in data: del data[field] - data.update(kwargs['initial']) + data.update(kwargs["initial"]) if page.template.child_template: - data['template_key'] = page.template.child_template - kwargs['initial'] = data + data["template_key"] = page.template.child_template + kwargs["initial"] = data except self.page_model.DoesNotExist: pass - elif 'translation_of' in kwargs['initial']: + elif "translation_of" in kwargs["initial"]: # Only if translation extension is active try: - page = self.page_manager.get( - pk=kwargs['initial']['translation_of']) + page = self.page_manager.get(pk=kwargs["initial"]["translation_of"]) original = page.original_translation data = { - 'translation_of': original.id, - 'template_key': original.template_key, - 'active': original.active, - 'in_navigation': original.in_navigation, + "translation_of": original.id, + "template_key": original.template_key, + "active": original.active, + "in_navigation": original.in_navigation, } if original.parent: try: - data['parent'] = original.parent.get_translation( - kwargs['initial']['language'] + data["parent"] = original.parent.get_translation( + kwargs["initial"]["language"] ).id except self.page_model.DoesNotExist: # ignore this -- the translation does not exist pass - data.update(kwargs['initial']) - kwargs['initial'] = data + data.update(kwargs["initial"]) + kwargs["initial"] = data except (AttributeError, self.page_model.DoesNotExist): pass # Not required, only a nice-to-have for the `redirect_to` field - modeladmin = kwargs.pop('modeladmin', None) + modeladmin = kwargs.pop("modeladmin", None) super(PageAdminForm, self).__init__(*args, **kwargs) - if modeladmin and 'redirect_to' in self.fields: + if modeladmin and "redirect_to" in self.fields: # Note: Using `parent` is not strictly correct, but we can be # sure that `parent` always points to another page instance, # and that's good enough for us. - field = self.page_model._meta.get_field('parent') - self.fields['redirect_to'].widget = RedirectToWidget( - field.remote_field if hasattr(field, 'remote_field') else field.rel, # noqa - modeladmin.admin_site) - - if 'template_key' in self.fields: + field = self.page_model._meta.get_field("parent") + self.fields["redirect_to"].widget = RedirectToWidget( + field.remote_field + if hasattr(field, "remote_field") + else field.rel, # noqa + modeladmin.admin_site, + ) + + if "template_key" in self.fields: choices = [] for key, template_name in self.page_model.TEMPLATE_CHOICES: template = self.page_model._feincms_templates[key] pages_for_template = self.page_model._default_manager.filter( - template_key=key) - pk = kwargs['instance'].pk if kwargs.get('instance') else None + template_key=key + ) + pk = kwargs["instance"].pk if kwargs.get("instance") else None other_pages_for_template = pages_for_template.exclude(pk=pk) if template.singleton and other_pages_for_template.exists(): continue # don't allow selection of singleton if in use if template.preview_image: - choices.append(( - template.key, - mark_safe('%s %s' % ( - template.preview_image, + choices.append( + ( template.key, - template.title, - )) - )) + mark_safe( + '%s %s' + % (template.preview_image, template.key, template.title) + ), + ) + ) else: choices.append((template.key, template.title)) - self.fields['template_key'].choices = choices + self.fields["template_key"].choices = choices def clean(self): cleaned_data = super(PageAdminForm, self).clean() @@ -160,18 +173,21 @@ def clean(self): current_id = self.instance.id active_pages = active_pages.exclude(id=current_id) - sites_is_installed = apps.is_installed('django.contrib.sites') - if sites_is_installed and 'site' in cleaned_data: - active_pages = active_pages.filter(site=cleaned_data['site']) + sites_is_installed = apps.is_installed("django.contrib.sites") + if sites_is_installed and "site" in cleaned_data: + active_pages = active_pages.filter(site=cleaned_data["site"]) # Convert PK in redirect_to field to something nicer for the future - redirect_to = cleaned_data.get('redirect_to') - if redirect_to and re.match(r'^\d+$', redirect_to): + redirect_to = cleaned_data.get("redirect_to") + if redirect_to and re.match(r"^\d+$", redirect_to): opts = self.page_model._meta - cleaned_data['redirect_to'] = '%s.%s:%s' % ( - opts.app_label, opts.model_name, redirect_to) + cleaned_data["redirect_to"] = "%s.%s:%s" % ( + opts.app_label, + opts.model_name, + redirect_to, + ) - if 'active' in cleaned_data and not cleaned_data['active']: + if "active" in cleaned_data and not cleaned_data["active"]: # If the current item is inactive, we do not need to conduct # further validation. Note that we only check for the flag, not # for any other active filters. This is because we do not want @@ -179,12 +195,12 @@ def clean(self): # really won't be active at the same time. return cleaned_data - if 'override_url' in cleaned_data and cleaned_data['override_url']: - if active_pages.filter( - _cached_url=cleaned_data['override_url']).count(): - self._errors['override_url'] = self.error_class([ - _('This URL is already taken by an active page.')]) - del cleaned_data['override_url'] + if "override_url" in cleaned_data and cleaned_data["override_url"]: + if active_pages.filter(_cached_url=cleaned_data["override_url"]).count(): + self._errors["override_url"] = self.error_class( + [_("This URL is already taken by an active page.")] + ) + del cleaned_data["override_url"] return cleaned_data @@ -193,24 +209,27 @@ def clean(self): parent = self.page_manager.get(pk=current_id).parent else: # The user tries to create a new page - parent = cleaned_data['parent'] + parent = cleaned_data["parent"] if parent: - new_url = '%s%s/' % (parent._cached_url, cleaned_data['slug']) + new_url = "%s%s/" % (parent._cached_url, cleaned_data["slug"]) else: - new_url = '/%s/' % cleaned_data['slug'] + new_url = "/%s/" % cleaned_data["slug"] if active_pages.filter(_cached_url=new_url).count(): - self._errors['active'] = self.error_class([ - _('This URL is already taken by another active page.')]) - del cleaned_data['active'] + self._errors["active"] = self.error_class( + [_("This URL is already taken by another active page.")] + ) + del cleaned_data["active"] if parent and parent.template.enforce_leaf: - self._errors['parent'] = self.error_class( - [_('This page does not allow attachment of child pages')]) - del cleaned_data['parent'] + self._errors["parent"] = self.error_class( + [_("This page does not allow attachment of child pages")] + ) + del cleaned_data["parent"] return cleaned_data + # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index a913c0db8..4a6847537 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -15,6 +15,7 @@ from django.http import HttpResponseRedirect from django.utils.functional import curry from django.utils.translation import ugettext_lazy as _ + try: from django.urls import reverse except ImportError: @@ -41,57 +42,58 @@ class Media: fieldset_insertion_index = 2 fieldsets = [ - (None, { - 'fields': [ - ('title', 'slug'), - ('active', 'in_navigation'), - ], - }), - (_('Other options'), { - 'classes': ['collapse'], - 'fields': [ - 'template_key', 'parent', 'override_url', 'redirect_to'], - }), + (None, {"fields": [("title", "slug"), ("active", "in_navigation")]}), + ( + _("Other options"), + { + "classes": ["collapse"], + "fields": ["template_key", "parent", "override_url", "redirect_to"], + }, + ), # <-- insertion point, extensions appear here, see insertion_index # above item_editor.FEINCMS_CONTENT_FIELDSET, ] readonly_fields = [] list_display = [ - 'short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] - list_filter = ['active', 'in_navigation', 'template_key', 'parent'] - search_fields = ['title', 'slug'] - prepopulated_fields = {'slug': ('title',)} + "short_title", + "is_visible_admin", + "in_navigation_toggle", + "template", + ] + list_filter = ["active", "in_navigation", "template_key", "parent"] + search_fields = ["title", "slug"] + prepopulated_fields = {"slug": ("title",)} - raw_id_fields = ['parent'] - radio_fields = {'template_key': admin.HORIZONTAL} + raw_id_fields = ["parent"] + radio_fields = {"template_key": admin.HORIZONTAL} @classmethod def add_extension_options(cls, *f): - if isinstance(f[-1], dict): # called with a fieldset + if isinstance(f[-1], dict): # called with a fieldset cls.fieldsets.insert(cls.fieldset_insertion_index, f) - f[1]['classes'] = list(f[1].get('classes', [])) - f[1]['classes'].append('collapse') - else: # assume called with "other" fields - cls.fieldsets[1][1]['fields'].extend(f) + f[1]["classes"] = list(f[1].get("classes", [])) + f[1]["classes"].append("collapse") + else: # assume called with "other" fields + cls.fieldsets[1][1]["fields"].extend(f) def __init__(self, model, admin_site): ensure_completely_loaded() - if len(model._feincms_templates) > 4 and \ - 'template_key' in self.radio_fields: - del(self.radio_fields['template_key']) + if len(model._feincms_templates) > 4 and "template_key" in self.radio_fields: + del (self.radio_fields["template_key"]) super(PageAdmin, self).__init__(model, admin_site) in_navigation_toggle = tree_editor.ajax_editable_boolean( - 'in_navigation', _('in navigation')) + "in_navigation", _("in navigation") + ) def get_readonly_fields(self, request, obj=None): readonly = super(PageAdmin, self).get_readonly_fields(request, obj=obj) if not settings.FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED: if obj and obj.template and obj.template.singleton: - return tuple(readonly) + ('template_key',) + return tuple(readonly) + ("template_key",) return readonly def get_form(self, *args, **kwargs): @@ -99,11 +101,12 @@ def get_form(self, *args, **kwargs): return curry(form, modeladmin=self) def _actions_column(self, page): - addable = getattr(page, 'feincms_addable', True) + addable = getattr(page, "feincms_addable", True) preview_url = "../../r/%s/%s/" % ( ContentType.objects.get_for_model(self.model).id, - page.id) + page.id, + ) actions = super(PageAdmin, self)._actions_column(page) if addable: @@ -112,61 +115,63 @@ def _actions_column(self, page): 0, '' '%s' - '' % ( + "" + % ( page.pk, - _('Add child page'), - static('feincms/img/icon_addlink.gif'), - _('Add child page'), - ) + _("Add child page"), + static("feincms/img/icon_addlink.gif"), + _("Add child page"), + ), ) actions.insert( 0, '' '%s' - '' % ( + "" + % ( preview_url, - _('View on site'), - static('feincms/img/selector-search.gif'), - _('View on site'), - ) + _("View on site"), + static("feincms/img/selector-search.gif"), + _("View on site"), + ), ) return actions def add_view(self, request, **kwargs): - kwargs['form_url'] = request.get_full_path() # Preserve GET parameters - if 'translation_of' in request.GET and 'language' in request.GET: + kwargs["form_url"] = request.get_full_path() # Preserve GET parameters + if "translation_of" in request.GET and "language" in request.GET: try: original = self.model._tree_manager.get( - pk=request.GET.get('translation_of')) + pk=request.GET.get("translation_of") + ) except (AttributeError, self.model.DoesNotExist): pass else: - language_code = request.GET['language'] - language = dict( - django_settings.LANGUAGES).get(language_code, '') - kwargs['extra_context'] = { - 'adding_translation': True, - 'title': _( - 'Add %(language)s translation of "%(page)s"') % { - 'language': language, - 'page': original, - }, - 'language_name': language, - 'translation_of': original, + language_code = request.GET["language"] + language = dict(django_settings.LANGUAGES).get(language_code, "") + kwargs["extra_context"] = { + "adding_translation": True, + "title": _('Add %(language)s translation of "%(page)s"') + % {"language": language, "page": original}, + "language_name": language, + "translation_of": original, } return super(PageAdmin, self).add_view(request, **kwargs) def response_add(self, request, obj, *args, **kwargs): - response = super(PageAdmin, self).response_add( - request, obj, *args, **kwargs) - if ('parent' in request.GET and - '_addanother' in request.POST and - response.status_code in (301, 302)): + response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) + if ( + "parent" in request.GET + and "_addanother" in request.POST + and response.status_code in (301, 302) + ): # Preserve GET parameters if we are about to add another page - response['Location'] += '?parent=%s' % request.GET['parent'] + response["Location"] += "?parent=%s" % request.GET["parent"] - if ('translation_of' in request.GET and - '_copy_content_from_original' in request.POST): + if ( + "translation_of" in request.GET + and "_copy_content_from_original" in request.POST + ): # Copy all contents for content_type in obj._feincms_content_types: if content_type.objects.filter(parent=obj).exists(): @@ -176,14 +181,19 @@ def response_add(self, request, obj, *args, **kwargs): try: original = self.model._tree_manager.get( - pk=request.GET.get('translation_of')) + pk=request.GET.get("translation_of") + ) original = original.original_translation obj.copy_content_from(original) obj.save() - self.message_user(request, _( - 'The content from the original translation has been copied' - ' to the newly created page.')) + self.message_user( + request, + _( + "The content from the original translation has been copied" + " to the newly created page." + ), + ) except (AttributeError, self.model.DoesNotExist): pass @@ -191,18 +201,14 @@ def response_add(self, request, obj, *args, **kwargs): def change_view(self, request, object_id, **kwargs): try: - return super(PageAdmin, self).change_view( - request, object_id, **kwargs) + return super(PageAdmin, self).change_view(request, object_id, **kwargs) except PermissionDenied: messages.add_message( request, messages.ERROR, - _( - "You don't have the necessary permissions to edit this" - " object" - ) + _("You don't have the necessary permissions to edit this" " object"), ) - return HttpResponseRedirect(reverse('admin:page_page_changelist')) + return HttpResponseRedirect(reverse("admin:page_page_changelist")) def has_delete_permission(self, request, obj=None): if not settings.FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED: @@ -212,7 +218,8 @@ def has_delete_permission(self, request, obj=None): def changelist_view(self, request, *args, **kwargs): _local.visible_pages = list( - self.model.objects.active().values_list('id', flat=True)) + self.model.objects.active().values_list("id", flat=True) + ) return super(PageAdmin, self).changelist_view(request, *args, **kwargs) def is_visible_admin(self, page): @@ -225,30 +232,36 @@ def is_visible_admin(self, page): if page.id in _local.visible_pages: _local.visible_pages.remove(page.id) return tree_editor.ajax_editable_boolean_cell( - page, 'active', override=False, text=_('inherited')) + page, "active", override=False, text=_("inherited") + ) if page.active and page.id not in _local.visible_pages: # is active but should not be shown, so visibility limited by # extension: show a "not active" return tree_editor.ajax_editable_boolean_cell( - page, 'active', override=False, text=_('extensions')) + page, "active", override=False, text=_("extensions") + ) + + return tree_editor.ajax_editable_boolean_cell(page, "active") - return tree_editor.ajax_editable_boolean_cell(page, 'active') - is_visible_admin.short_description = _('is active') - is_visible_admin.editable_boolean_field = 'active' + is_visible_admin.short_description = _("is active") + is_visible_admin.editable_boolean_field = "active" # active toggle needs more sophisticated result function def is_visible_recursive(self, page): # Have to refresh visible_pages here, because TreeEditor.toggle_boolean # will have changed the value when inside this code path. _local.visible_pages = list( - self.model.objects.active().values_list('id', flat=True)) + self.model.objects.active().values_list("id", flat=True) + ) retval = [] for c in page.get_descendants(include_self=True): retval.append(self.is_visible_admin(c)) return retval + is_visible_admin.editable_boolean_result = is_visible_recursive + # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 1f6f5262f..10932feec 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -10,6 +10,7 @@ from django.http import Http404 from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ + try: from django.urls import reverse except ImportError: @@ -22,9 +23,7 @@ from feincms.module.mixins import ContentModelMixin from feincms.module.page import processors from feincms.utils.managers import ActiveAwareContentManagerMixin -from feincms.utils import ( - shorten_string, match_model_string, get_model_instance -) +from feincms.utils import shorten_string, match_model_string, get_model_instance # ------------------------------------------------------------------------ @@ -35,8 +34,7 @@ class BasePageManager(ActiveAwareContentManagerMixin, TreeManager): """ # The fields which should be excluded when creating a copy. - exclude_from_copy = [ - 'id', 'tree_id', 'lft', 'rght', 'level', 'redirect_to'] + exclude_from_copy = ["id", "tree_id", "lft", "rght", "level", "redirect_to"] def page_for_path(self, path, raise404=False): """ @@ -47,14 +45,13 @@ def page_for_path(self, path, raise404=False): Page.objects.page_for_path(request.path) """ - stripped = path.strip('/') + stripped = path.strip("/") try: - page = self.active().get( - _cached_url='/%s/' % stripped if stripped else '/') + page = self.active().get(_cached_url="/%s/" % stripped if stripped else "/") if not page.are_ancestors_active(): - raise self.model.DoesNotExist('Parents are inactive.') + raise self.model.DoesNotExist("Parents are inactive.") return page @@ -75,22 +72,23 @@ def best_match_for_path(self, path, raise404=False): page with url '/photos/album/'. """ - paths = ['/'] - path = path.strip('/') + paths = ["/"] + path = path.strip("/") if path: - tokens = path.split('/') - paths += [ - '/%s/' % '/'.join(tokens[:i]) - for i in range(1, len(tokens) + 1)] + tokens = path.split("/") + paths += ["/%s/" % "/".join(tokens[:i]) for i in range(1, len(tokens) + 1)] try: - page = self.active().filter(_cached_url__in=paths).extra( - select={'_url_length': 'LENGTH(_cached_url)'} - ).order_by('-_url_length')[0] + page = ( + self.active() + .filter(_cached_url__in=paths) + .extra(select={"_url_length": "LENGTH(_cached_url)"}) + .order_by("-_url_length")[0] + ) if not page.are_ancestors_active(): - raise IndexError('Parents are inactive.') + raise IndexError("Parents are inactive.") return page @@ -114,8 +112,7 @@ def toplevel_navigation(self): return self.in_navigation().filter(parent__isnull=True) - def for_request(self, request, raise404=False, best_match=False, - path=None): + def for_request(self, request, raise404=False, best_match=False, path=None): """ Return a page for the request @@ -129,15 +126,15 @@ def for_request(self, request, raise404=False, best_match=False, could be determined. """ - if not hasattr(request, '_feincms_page'): + if not hasattr(request, "_feincms_page"): path = path or request.path_info or request.path if best_match: request._feincms_page = self.best_match_for_path( - path, raise404=raise404) + path, raise404=raise404 + ) else: - request._feincms_page = self.page_for_path( - path, raise404=raise404) + request._feincms_page = self.page_for_path(path, raise404=raise404) return request._feincms_page @@ -147,45 +144,65 @@ class PageManager(BasePageManager): pass -PageManager.add_to_active_filters(Q(active=True), key='is_active') +PageManager.add_to_active_filters(Q(active=True), key="is_active") # ------------------------------------------------------------------------ @python_2_unicode_compatible class BasePage(create_base_model(MPTTModel), ContentModelMixin): - active = models.BooleanField(_('active'), default=True) + active = models.BooleanField(_("active"), default=True) # structure and navigation - title = models.CharField(_('title'), max_length=200, help_text=_( - 'This title is also used for navigation menu items.')) + title = models.CharField( + _("title"), + max_length=200, + help_text=_("This title is also used for navigation menu items."), + ) slug = models.SlugField( - _('slug'), max_length=150, - help_text=_('This is used to build the URL for this page')) + _("slug"), + max_length=150, + help_text=_("This is used to build the URL for this page"), + ) parent = models.ForeignKey( - 'self', verbose_name=_('Parent'), blank=True, + "self", + verbose_name=_("Parent"), + blank=True, on_delete=models.CASCADE, - null=True, related_name='children') + null=True, + related_name="children", + ) # Custom list_filter - see admin/filterspecs.py parent.parent_filter = True - in_navigation = models.BooleanField(_('in navigation'), default=False) + in_navigation = models.BooleanField(_("in navigation"), default=False) override_url = models.CharField( - _('override URL'), max_length=255, - blank=True, help_text=_( - 'Override the target URL. Be sure to include slashes at the ' - 'beginning and at the end if it is a local URL. This ' - 'affects both the navigation and subpages\' URLs.')) + _("override URL"), + max_length=255, + blank=True, + help_text=_( + "Override the target URL. Be sure to include slashes at the " + "beginning and at the end if it is a local URL. This " + "affects both the navigation and subpages' URLs." + ), + ) redirect_to = models.CharField( - _('redirect to'), max_length=255, + _("redirect to"), + max_length=255, blank=True, help_text=_( - 'Target URL for automatic redirects' - ' or the primary key of a page.')) + "Target URL for automatic redirects" " or the primary key of a page." + ), + ) _cached_url = models.CharField( - _('Cached URL'), max_length=255, blank=True, - editable=False, default='', db_index=True) + _("Cached URL"), + max_length=255, + blank=True, + editable=False, + default="", + db_index=True, + ) class Meta: - ordering = ['tree_id', 'lft'] + ordering = ["tree_id", "lft"] abstract = True objects = PageManager() @@ -206,11 +223,11 @@ def is_active(self): return False pages = self.__class__.objects.active().filter( - tree_id=self.tree_id, - lft__lte=self.lft, - rght__gte=self.rght) + tree_id=self.tree_id, lft__lte=self.lft, rght__gte=self.rght + ) return pages.count() > self.level - is_active.short_description = _('is active') + + is_active.short_description = _("is active") def are_ancestors_active(self): """ @@ -228,8 +245,9 @@ def short_title(self): Title shortened for display. """ return shorten_string(self.title) - short_title.admin_order_field = 'title' - short_title.short_description = _('title') + + short_title.admin_order_field = "title" + short_title.short_description = _("title") def __init__(self, *args, **kwargs): super(BasePage, self).__init__(*args, **kwargs) @@ -250,9 +268,9 @@ def save(self, *args, **kwargs): if self.override_url: self._cached_url = self.override_url elif self.is_root_node(): - self._cached_url = '/%s/' % self.slug + self._cached_url = "/%s/" % self.slug else: - self._cached_url = '%s%s/' % (self.parent._cached_url, self.slug) + self._cached_url = "%s%s/" % (self.parent._cached_url, self.slug) cached_page_urls[self.id] = self._cached_url super(BasePage, self).save(*args, **kwargs) @@ -264,29 +282,35 @@ def save(self, *args, **kwargs): if self._cached_url == self._original_cached_url: return - pages = self.get_descendants().order_by('lft') + pages = self.get_descendants().order_by("lft") for page in pages: if page.override_url: page._cached_url = page.override_url else: # cannot be root node by definition - page._cached_url = '%s%s/' % ( + page._cached_url = "%s%s/" % ( cached_page_urls[page.parent_id], - page.slug) + page.slug, + ) cached_page_urls[page.id] = page._cached_url super(BasePage, page).save() # do not recurse + save.alters_data = True def delete(self, *args, **kwargs): if not settings.FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED: if self.template.singleton: - raise PermissionDenied(_( - 'This %(page_class)s uses a singleton template, and ' - 'FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False' % { - 'page_class': self._meta.verbose_name})) + raise PermissionDenied( + _( + "This %(page_class)s uses a singleton template, and " + "FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED=False" + % {"page_class": self._meta.verbose_name} + ) + ) super(BasePage, self).delete(*args, **kwargs) + delete.alters_data = True def get_absolute_url(self): @@ -294,10 +318,10 @@ def get_absolute_url(self): Return the absolute URL of this page. """ # result url never begins or ends with a slash - url = self._cached_url.strip('/') + url = self._cached_url.strip("/") if url: - return reverse('feincms_handler', args=(url,)) - return reverse('feincms_home') + return reverse("feincms_handler", args=(url,)) + return reverse("feincms_home") def get_navigation_url(self): """ @@ -360,18 +384,20 @@ def register_default_processors(cls): Page experience. """ cls.register_request_processor( - processors.redirect_request_processor, key='redirect') + processors.redirect_request_processor, key="redirect" + ) cls.register_request_processor( - processors.extra_context_request_processor, key='extra_context') + processors.extra_context_request_processor, key="extra_context" + ) # ------------------------------------------------------------------------ class Page(BasePage): class Meta: - ordering = ['tree_id', 'lft'] - verbose_name = _('page') - verbose_name_plural = _('pages') - app_label = 'page' + ordering = ["tree_id", "lft"] + verbose_name = _("page") + verbose_name_plural = _("pages") + app_label = "page" # not yet # permissions = (("edit_page", _("Can edit page metadata")),) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 44441e824..894e4c0f9 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -18,12 +18,14 @@ def redirect_request_processor(page, request): """ target = page.get_redirect_to_target(request) if target: - extra_path = request._feincms_extra_context.get('extra_path', '/') - if extra_path == '/': + extra_path = request._feincms_extra_context.get("extra_path", "/") + if extra_path == "/": return HttpResponseRedirect(target) logger.debug( "Page redirect on '%s' not taken because extra path '%s' present", - page.get_absolute_url(), extra_path) + page.get_absolute_url(), + extra_path, + ) raise Http404() @@ -31,22 +33,24 @@ def extra_context_request_processor(page, request): """ Fills ``request._feincms_extra_context`` with a few useful variables. """ - request._feincms_extra_context.update({ - # XXX This variable name isn't accurate anymore. - 'in_appcontent_subpage': False, - 'extra_path': '/', - }) + request._feincms_extra_context.update( + { + # XXX This variable name isn't accurate anymore. + "in_appcontent_subpage": False, + "extra_path": "/", + } + ) url = page.get_absolute_url() if request.path != url: - request._feincms_extra_context.update({ - 'in_appcontent_subpage': True, - 'extra_path': re.sub( - '^' + re.escape(url.rstrip('/')), - '', - request.path, - ), - }) + request._feincms_extra_context.update( + { + "in_appcontent_subpage": True, + "extra_path": re.sub( + "^" + re.escape(url.rstrip("/")), "", request.path + ), + } + ) def etag_request_processor(page, request): @@ -62,6 +66,7 @@ class DummyResponse(dict): This is a dummy class with enough behaviour of HttpResponse so we can use the condition decorator without too much pain. """ + def has_header(page, what): return False @@ -85,7 +90,8 @@ def lastmodifier(request, page, *args, **kwargs): # the handler if processing is to continue and a non-DummyResponse # (should be a "304 not modified") if the etag matches. rsp = condition(etag_func=etagger, last_modified_func=lastmodifier)( - dummy_response_handler)(request, page) + dummy_response_handler + )(request, page) # If dummy then don't do anything, if a real response, return and # thus shortcut the request processing. @@ -101,7 +107,7 @@ def etag_response_processor(page, request, response): """ etag = page.etag(request) if etag is not None: - response['ETag'] = '"' + etag + '"' + response["ETag"] = '"' + etag + '"' def debug_sql_queries_response_processor(verbose=False, file=sys.stderr): @@ -127,9 +133,10 @@ def processor(page, request, response): import sqlparse def print_sql(x): - return sqlparse.format( - x, reindent=True, keyword_case='upper') + return sqlparse.format(x, reindent=True, keyword_case="upper") + except Exception: + def print_sql(x): return x @@ -140,9 +147,10 @@ def print_sql(x): for q in connection.queries: i += 1 if verbose: - print("%d : [%s]\n%s\n" % ( - i, q['time'], print_sql(q['sql'])), file=file) - time += float(q['time']) + print( + "%d : [%s]\n%s\n" % (i, q["time"], print_sql(q["sql"])), file=file + ) + time += float(q["time"]) print("-" * 60, file=file) print("Total: %d queries, %.3f ms" % (i, time), file=file) diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index 40f2853d4..c5cbd5850 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -17,10 +17,19 @@ class PageSitemap(Sitemap): The PageSitemap can be used to automatically generate sitemap.xml files for submission to index engines. See http://www.sitemaps.org/ for details. """ - def __init__(self, navigation_only=False, max_depth=0, changefreq=None, - queryset=None, filter=None, extended_navigation=False, - page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL, - *args, **kwargs): + + def __init__( + self, + navigation_only=False, + max_depth=0, + changefreq=None, + queryset=None, + filter=None, + extended_navigation=False, + page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL, + *args, + **kwargs + ): """ The PageSitemap accepts the following parameters for customisation of the resulting sitemap.xml output: @@ -48,7 +57,7 @@ def __init__(self, navigation_only=False, max_depth=0, changefreq=None, if queryset is not None: self.queryset = queryset else: - Page = apps.get_model(*page_model.split('.')) + Page = apps.get_model(*page_model.split(".")) self.queryset = Page.objects.active() def items(self): @@ -60,7 +69,7 @@ def items(self): if callable(base_qs): base_qs = base_qs() - self.max_depth = base_qs.aggregate(Max('level'))['level__max'] or 0 + self.max_depth = base_qs.aggregate(Max("level"))["level__max"] or 0 if self.depth_cutoff > 0: self.max_depth = min(self.depth_cutoff, self.max_depth) @@ -78,14 +87,13 @@ def items(self): for idx, page in enumerate(pages): if self.depth_cutoff > 0 and page.level == self.max_depth: continue - if getattr(page, 'navigation_extension', None): + if getattr(page, "navigation_extension", None): cnt = 0 for p in page.extended_navigation(): depth_too_deep = ( - self.depth_cutoff > 0 and - p.level > self.depth_cutoff) - not_in_nav = ( - self.navigation_only and not p.in_navigation) + self.depth_cutoff > 0 and p.level > self.depth_cutoff + ) + not_in_nav = self.navigation_only and not p.in_navigation if depth_too_deep or not_in_nav: continue cnt += 1 @@ -97,7 +105,7 @@ def items(self): return pages def lastmod(self, obj): - return getattr(obj, 'modification_date', None) + return getattr(obj, "modification_date", None) # the priority is computed of the depth in the tree of a page # may we should make an extension to give control to the user for priority @@ -107,7 +115,7 @@ def priority(self, obj): the site. Top level get highest priority, then each level is decreased by per_level. """ - if getattr(obj, 'override_url', '') == '/': + if getattr(obj, "override_url", "") == "/": prio = 1.0 else: prio = 1.0 - (obj.level + 1) * self.per_level @@ -119,4 +127,5 @@ def priority(self, obj): return "%0.2g" % min(1.0, prio) + # ------------------------------------------------------------------------ diff --git a/feincms/shortcuts.py b/feincms/shortcuts.py index 936460915..a24be3fe5 100644 --- a/feincms/shortcuts.py +++ b/feincms/shortcuts.py @@ -11,6 +11,6 @@ def render_to_response_best_match(request, template_name, dictionary=None): """ dictionary = dictionary or {} - dictionary['feincms_page'] = Page.objects.best_match_for_request(request) + dictionary["feincms_page"] = Page.objects.best_match_for_request(request) return render(request, template_name, dictionary) diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index 531e94eda..37dd2aae2 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -4,6 +4,7 @@ from django.template import TemplateSyntaxError from django.template.defaulttags import kwarg_re from django.utils.encoding import smart_str + try: from django.urls import NoReverseMatch except ImportError: @@ -11,9 +12,9 @@ from feincms.apps import ApplicationContent, app_reverse as do_app_reverse from feincms.templatetags.feincms_tags import _render_content + # backwards compatibility import -from feincms.templatetags.fragment_tags import ( - fragment, get_fragment, has_fragment) +from feincms.templatetags.fragment_tags import fragment, get_fragment, has_fragment register = template.Library() @@ -37,10 +38,11 @@ def feincms_render_region_appcontent(page, region, request): {% feincms_render_region_appcontent feincms_page "main" request %} {% endif %} """ - return ''.join( + return "".join( _render_content(content, request=request) for content in page.content.all_of_type(ApplicationContent) - if content.region == region) + if content.region == region + ) def _current_app(context): @@ -50,7 +52,7 @@ def _current_app(context): try: return context.request.resolver_match.namespace except AttributeError: - return getattr(context, 'current_app', None) + return getattr(context, "current_app", None) class AppReverseNode(template.Node): @@ -63,24 +65,31 @@ def __init__(self, view_name, urlconf, args, kwargs, asvar): def render(self, context): args = [arg.resolve(context) for arg in self.args] - kwargs = dict([ - (smart_str(k, 'ascii'), v.resolve(context)) - for k, v in self.kwargs.items()]) + kwargs = dict( + [ + (smart_str(k, "ascii"), v.resolve(context)) + for k, v in self.kwargs.items() + ] + ) view_name = self.view_name.resolve(context) urlconf = self.urlconf.resolve(context) try: url = do_app_reverse( - view_name, urlconf, args=args, kwargs=kwargs, - current_app=_current_app(context)) + view_name, + urlconf, + args=args, + kwargs=kwargs, + current_app=_current_app(context), + ) except NoReverseMatch: if self.asvar is None: raise - url = '' + url = "" if self.asvar: context[self.asvar] = url - return '' + return "" else: return url @@ -118,14 +127,15 @@ def app_reverse(parser, token): if len(bits) < 3: raise TemplateSyntaxError( "'%s' takes at least two arguments" - " (path to a view and a urlconf)" % bits[0]) + " (path to a view and a urlconf)" % bits[0] + ) viewname = parser.compile_filter(bits[1]) urlconf = parser.compile_filter(bits[2]) args = [] kwargs = {} asvar = None bits = bits[3:] - if len(bits) >= 2 and bits[-2] == 'as': + if len(bits) >= 2 and bits[-2] == "as": asvar = bits[-1] bits = bits[:-2] @@ -133,8 +143,7 @@ def app_reverse(parser, token): for bit in bits: match = kwarg_re.match(bit) if not match: - raise TemplateSyntaxError( - "Malformed arguments to app_reverse tag") + raise TemplateSyntaxError("Malformed arguments to app_reverse tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py index 5292b410f..e8127eb39 100644 --- a/feincms/templatetags/feincms_admin_tags.py +++ b/feincms/templatetags/feincms_admin_tags.py @@ -23,7 +23,7 @@ def post_process_fieldsets(context, fieldset): return fieldset fields_to_include = set(fieldset.form.fields.keys()) - for f in ('id', 'DELETE', 'ORDER'): + for f in ("id", "DELETE", "ORDER"): fields_to_include.discard(f) def _filter_recursive(fields): @@ -46,37 +46,38 @@ def _filter_recursive(fields): for f in fields_to_include: new_fields.append(f) - if context.get('request'): - new_fields.extend(list( - fieldset.model_admin.get_readonly_fields( - context.get('request'), - context.get('original'), + if context.get("request"): + new_fields.extend( + list( + fieldset.model_admin.get_readonly_fields( + context.get("request"), context.get("original") + ) ) - )) + ) fieldset.fields = new_fields - return '' + return "" -@register.inclusion_tag('admin/feincms/content_type_selection_widget.html', - takes_context=True) +@register.inclusion_tag( + "admin/feincms/content_type_selection_widget.html", takes_context=True +) def show_content_type_selection_widget(context, region): """ {% show_content_type_selection_widget region %} """ - user = context['request'].user + user = context["request"].user types = OrderedDict({None: []}) for ct in region._content_types: # Skip cts that we shouldn't be adding anyway opts = ct._meta - perm = opts.app_label + "." + get_permission_codename('add', opts) + perm = opts.app_label + "." + get_permission_codename("add", opts) if not user.has_perm(perm): continue - types.setdefault( - getattr(ct, 'optgroup', None), - [], - ).append((ct.__name__.lower, ct._meta.verbose_name)) + types.setdefault(getattr(ct, "optgroup", None), []).append( + (ct.__name__.lower, ct._meta.verbose_name) + ) - return {'types': types} + return {"types": types} diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index 2ea6cd7c1..60eca87c8 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -18,21 +18,20 @@ from feincms.module.page.extensions.navigation import PagePretender from feincms.utils.templatetags import ( SimpleAssignmentNodeWithVarAndArgs, - do_simple_assignment_node_with_var_and_args_helper) + do_simple_assignment_node_with_var_and_args_helper, +) -logger = logging.getLogger('feincms.templatetags.page') +logger = logging.getLogger("feincms.templatetags.page") register = template.Library() assignment_tag = ( - register.simple_tag if django.VERSION >= (1, 9) - else register.assignment_tag + register.simple_tag if django.VERSION >= (1, 9) else register.assignment_tag ) def _get_page_model(): - return apps.get_model( - *feincms_settings.FEINCMS_DEFAULT_PAGE_MODEL.split('.')) + return apps.get_model(*feincms_settings.FEINCMS_DEFAULT_PAGE_MODEL.split(".")) # ------------------------------------------------------------------------ @@ -56,8 +55,7 @@ def feincms_nav(context, feincms_page, level=1, depth=1, group=None): if isinstance(feincms_page, HttpRequest): try: - feincms_page = page_class.objects.for_request( - feincms_page, best_match=True) + feincms_page = page_class.objects.for_request(feincms_page, best_match=True) except page_class.DoesNotExist: return [] @@ -68,8 +66,8 @@ def feincms_nav(context, feincms_page, level=1, depth=1, group=None): queryset = feincms_page.__class__._default_manager.in_navigation().filter( **{ - '%s__gte' % mptt_opts.level_attr: mptt_level_range[0], - '%s__lt' % mptt_opts.level_attr: mptt_level_range[1], + "%s__gte" % mptt_opts.level_attr: mptt_level_range[0], + "%s__lt" % mptt_opts.level_attr: mptt_level_range[1], } ) @@ -98,10 +96,13 @@ def feincms_nav(context, feincms_page, level=1, depth=1, group=None): queryset = page_class.objects.none() if parent: - if getattr(parent, 'navigation_extension', None): + if getattr(parent, "navigation_extension", None): # Special case for navigation extensions - return list(parent.extended_navigation( - depth=depth, request=context.get('request'))) + return list( + parent.extended_navigation( + depth=depth, request=context.get("request") + ) + ) # Apply descendant filter queryset &= parent.get_descendants() @@ -126,40 +127,44 @@ def _parentactive_filter(iterable): # navigationgroups extension support def _navigationgroup_filter(iterable): for elem in iterable: - if getattr(elem, 'navigation_group', None) == group: + if getattr(elem, "navigation_group", None) == group: yield elem queryset = _navigationgroup_filter(queryset) - if hasattr(feincms_page, 'navigation_extension'): + if hasattr(feincms_page, "navigation_extension"): # Filter out children of nodes which have a navigation extension def _navext_filter(iterable): current_navextension_node = None for elem in iterable: # Eliminate all subitems of last processed nav extension - if current_navextension_node is not None and \ - current_navextension_node.is_ancestor_of(elem): + if ( + current_navextension_node is not None + and current_navextension_node.is_ancestor_of(elem) + ): continue yield elem - if getattr(elem, 'navigation_extension', None): + if getattr(elem, "navigation_extension", None): current_navextension_node = elem try: for extended in elem.extended_navigation( - depth=depth, request=context.get('request')): + depth=depth, request=context.get("request") + ): # Only return items from the extended navigation # which are inside the requested level+depth # values. The "-1" accounts for the differences in # MPTT and navigation level counting - this_level = getattr( - extended, mptt_opts.level_attr, 0) + this_level = getattr(extended, mptt_opts.level_attr, 0) if this_level < level + depth - 1: yield extended except Exception as e: logger.warn( "feincms_nav caught exception in navigation" " extension for page %d: %s", - current_navextension_node.id, format_exception(e)) + current_navextension_node.id, + format_exception(e), + ) else: current_navextension_node = None @@ -200,21 +205,19 @@ class LanguageLinksNode(SimpleAssignmentNodeWithVarAndArgs): """ def what(self, page, args): - only_existing = args.get('existing', False) - exclude_current = args.get('excludecurrent', False) + only_existing = args.get("existing", False) + exclude_current = args.get("excludecurrent", False) # Preserve the trailing path when switching languages if extra_path # exists (this is mostly the case when we are working inside an # ApplicationContent-managed page subtree) - trailing_path = '' - request = args.get('request', None) + trailing_path = "" + request = args.get("request", None) if request: # Trailing path without first slash - trailing_path = request._feincms_extra_context.get( - 'extra_path', '')[1:] + trailing_path = request._feincms_extra_context.get("extra_path", "")[1:] - translations = dict( - (t.language, t) for t in page.available_translations()) + translations = dict((t.language, t) for t in page.available_translations()) translations[page.language] = page links = [] @@ -224,10 +227,9 @@ def what(self, page, args): # hardcoded paths... bleh if key in translations: - links.append(( - key, - name, - translations[key].get_absolute_url() + trailing_path)) + links.append( + (key, name, translations[key].get_absolute_url() + trailing_path) + ) elif not only_existing: links.append((key, name, None)) @@ -235,8 +237,9 @@ def what(self, page, args): register.tag( - 'feincms_languagelinks', - do_simple_assignment_node_with_var_and_args_helper(LanguageLinksNode)) + "feincms_languagelinks", + do_simple_assignment_node_with_var_and_args_helper(LanguageLinksNode), +) # ------------------------------------------------------------------------ @@ -251,14 +254,13 @@ def _translate_page_into(page, language, default=None): return page if language is not None: - translations = dict( - (t.language, t) for t in page.available_translations()) + translations = dict((t.language, t) for t in page.available_translations()) if language in translations: return translations[language] except AttributeError: pass - if hasattr(default, '__call__'): + if hasattr(default, "__call__"): return default(page=page) return default @@ -284,16 +286,16 @@ class TranslatedPageNode(SimpleAssignmentNodeWithVarAndArgs): whether settings LANGUAGES contains that code -- so naming a variable "en" will probably not do what is intended. """ + def what(self, page, args, default=None): - language = args.get('language', None) + language = args.get("language", None) if language is None: language = settings.LANGUAGES[0][0] else: if language not in (x[0] for x in settings.LANGUAGES): try: - language = template.Variable(language).resolve( - self.render_context) + language = template.Variable(language).resolve(self.render_context) except template.VariableDoesNotExist: language = settings.LANGUAGES[0][0] @@ -301,32 +303,34 @@ def what(self, page, args, default=None): register.tag( - 'feincms_translatedpage', - do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNode)) + "feincms_translatedpage", + do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNode), +) # ------------------------------------------------------------------------ class TranslatedPageNodeOrBase(TranslatedPageNode): def what(self, page, args): return super(TranslatedPageNodeOrBase, self).what( - page, args, - default=getattr(page, 'get_original_translation', page)) + page, args, default=getattr(page, "get_original_translation", page) + ) register.tag( - 'feincms_translatedpage_or_base', - do_simple_assignment_node_with_var_and_args_helper( - TranslatedPageNodeOrBase)) + "feincms_translatedpage_or_base", + do_simple_assignment_node_with_var_and_args_helper(TranslatedPageNodeOrBase), +) # ------------------------------------------------------------------------ @register.filter def feincms_translated_or_base(pages, language=None): - if not hasattr(pages, '__iter__'): + if not hasattr(pages, "__iter__"): pages = [pages] for page in pages: yield _translate_page_into( - page, language, default=page.get_original_translation) + page, language, default=page.get_original_translation + ) # ------------------------------------------------------------------------ @@ -443,8 +447,10 @@ def siblings_along_path_to(page_list, page2): # comes from feincms_nav). We'll cope with the fall-out of that # assumption when it happens... ancestors = [ - a_page for a_page in page_list - if a_page.is_ancestor_of(page2, include_self=True)] + a_page + for a_page in page_list + if a_page.is_ancestor_of(page2, include_self=True) + ] top_level = min((a_page.level for a_page in page_list)) if not ancestors: @@ -454,25 +460,25 @@ def siblings_along_path_to(page_list, page2): page_class = _get_page_model() p = page_class( - title="dummy", - tree_id=-1, - parent_id=None, - in_navigation=False) + title="dummy", tree_id=-1, parent_id=None, in_navigation=False + ) ancestors = (p,) siblings = [ - a_page for a_page in page_list if ( - a_page.parent_id == page2.id or - a_page.level == top_level or - any((_is_sibling_of(a_page, a) for a in ancestors)) + a_page + for a_page in page_list + if ( + a_page.parent_id == page2.id + or a_page.level == top_level + or any((_is_sibling_of(a_page, a) for a in ancestors)) ) ] return siblings except (AttributeError, ValueError) as e: logger.warn( - "siblings_along_path_to caught exception: %s", - format_exception(e)) + "siblings_along_path_to caught exception: %s", format_exception(e) + ) return () @@ -495,25 +501,25 @@ def page_is_active(context, page, feincms_page=None, path=None): """ if isinstance(page, PagePretender): if path is None: - path = context['request'].path_info + path = context["request"].path_info return path.startswith(page.get_absolute_url()) else: if feincms_page is None: - feincms_page = context['feincms_page'] + feincms_page = context["feincms_page"] return page.is_ancestor_of(feincms_page, include_self=True) # ------------------------------------------------------------------------ @register.simple_tag def feincms_parentlink(of_, feincms_page, **kwargs): - level = int(kwargs.get('level', 1)) + level = int(kwargs.get("level", 1)) if feincms_page.level + 1 == level: return feincms_page.get_absolute_url() elif feincms_page.level + 1 < level: - return '#' + return "#" try: return feincms_page.get_ancestors()[level - 1].get_absolute_url() except IndexError: - return '#' + return "#" diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 1450d7ace..faeed6c57 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -16,8 +16,7 @@ register = template.Library() assignment_tag = ( - register.simple_tag if django.VERSION >= (1, 9) - else register.assignment_tag + register.simple_tag if django.VERSION >= (1, 9) else register.assignment_tag ) @@ -25,15 +24,15 @@ def _render_content(content, **kwargs): # Track current render level and abort if we nest too deep. Avoids # crashing in recursive page contents (eg. a page list that contains # itself or similar). - request = kwargs.get('request') + request = kwargs.get("request") if request is not None: - level = getattr(request, 'feincms_render_level', 0) + level = getattr(request, "feincms_render_level", 0) if level > 10: - logging.getLogger('feincms').error( - 'Refusing to render %r, render level is already %s' % ( - content, level)) + logging.getLogger("feincms").error( + "Refusing to render %r, render level is already %s" % (content, level) + ) return - setattr(request, 'feincms_render_level', level + 1) + setattr(request, "feincms_render_level", level + 1) r = content.render(**kwargs) @@ -62,8 +61,8 @@ def _render_content(content, **kwargs): return plugin_template.render(context) if request is not None: - level = getattr(request, 'feincms_render_level', 1) - setattr(request, 'feincms_render_level', max(level - 1, 0)) + level = getattr(request, "feincms_render_level", 1) + setattr(request, "feincms_render_level", max(level - 1, 0)) return r @@ -74,11 +73,14 @@ def feincms_render_region(context, feincms_object, region, request=None): {% feincms_render_region feincms_page "main" request %} """ if not feincms_object: - return '' + return "" - return mark_safe(''.join( - _render_content(content, request=request, context=context) - for content in getattr(feincms_object.content, region))) + return mark_safe( + "".join( + _render_content(content, request=request, context=context) + for content in getattr(feincms_object.content, region) + ) + ) @register.simple_tag(takes_context=True) @@ -87,7 +89,7 @@ def feincms_render_content(context, content, request=None): {% feincms_render_content content request %} """ if not content: - return '' + return "" return _render_content(content, request=request, context=context) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 09f397746..299889a74 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -19,16 +19,16 @@ from feincms import settings -logger = logging.getLogger('feincms.templatetags.thumbnail') +logger = logging.getLogger("feincms.templatetags.thumbnail") register = template.Library() @python_2_unicode_compatible class Thumbnailer(object): - THUMBNAIL_SIZE_RE = re.compile(r'^(?P\d+)x(?P\d+)$') - MARKER = '_thumb_' + THUMBNAIL_SIZE_RE = re.compile(r"^(?P\d+)x(?P\d+)$") + MARKER = "_thumb_" - def __init__(self, filename, size='200x200'): + def __init__(self, filename, size="200x200"): self.filename = filename self.size = size @@ -39,39 +39,41 @@ def url(self): def __str__(self): match = self.THUMBNAIL_SIZE_RE.match(self.size) if not (self.filename and match): - return '' + return "" matches = match.groupdict() # figure out storage - if hasattr(self.filename, 'storage'): + if hasattr(self.filename, "storage"): storage = self.filename.storage else: storage = default_storage # figure out name - if hasattr(self.filename, 'name'): + if hasattr(self.filename, "name"): filename = self.filename.name else: filename = force_text(self.filename) # defining the filename and the miniature filename try: - basename, format = filename.rsplit('.', 1) + basename, format = filename.rsplit(".", 1) except ValueError: - basename, format = filename, 'jpg' - - miniature = ''.join([ - settings.FEINCMS_THUMBNAIL_DIR, - basename, - self.MARKER, - self.size, - '.', - format, - ]) + basename, format = filename, "jpg" + + miniature = "".join( + [ + settings.FEINCMS_THUMBNAIL_DIR, + basename, + self.MARKER, + self.size, + ".", + format, + ] + ) if settings.FEINCMS_THUMBNAIL_CACHE_TIMEOUT != 0: - cache_key = 'thumb_url_%s' % miniature + cache_key = "thumb_url_%s" % miniature url = cache.get(cache_key) if url: return url @@ -80,15 +82,15 @@ def __str__(self): generate = True else: try: - generate = ( - storage.modified_time(miniature) < - storage.modified_time(filename)) + generate = storage.modified_time(miniature) < storage.modified_time( + filename + ) except (NotImplementedError, AttributeError): # storage does NOT support modified_time generate = False except (OSError, IOError): # Someone might have delete the file - return '' + return "" if generate: try: @@ -96,13 +98,15 @@ def __str__(self): storage=storage, original=filename, size=matches, - miniature=miniature) + miniature=miniature, + ) except Exception as exc: logger.warning( - 'Rendering a thumbnail failed: %r', + "Rendering a thumbnail failed: %r", exc, exc_info=True, - extra={'stack': True, 'exception': exc}) + extra={"stack": True, "exception": exc}, + ) # PIL raises a plethora of Exceptions if reading the image # is not possible. Since we cannot be sure what Exception will # happen, catch them all so the thumbnailer will never fail. @@ -110,11 +114,7 @@ def __str__(self): url = storage.url(miniature) if settings.FEINCMS_THUMBNAIL_CACHE_TIMEOUT != 0: - cache.set( - cache_key, - url, - timeout=settings.FEINCMS_THUMBNAIL_CACHE_TIMEOUT - ) + cache.set(cache_key, url, timeout=settings.FEINCMS_THUMBNAIL_CACHE_TIMEOUT) return url def generate(self, storage, original, size, miniature): @@ -123,15 +123,15 @@ def generate(self, storage, original, size, miniature): image = Image.open(original_bytes) # defining the size - w, h = int(size['w']), int(size['h']) + w, h = int(size["w"]), int(size["h"]) format = image.format # Save format for the save() call later image.thumbnail([w, h], Image.ANTIALIAS) buf = BytesIO() - if image.mode not in ('RGBA', 'RGB', 'L'): - image = image.convert('RGBA') - if format.lower() not in ('jpg', 'jpeg', 'png'): - format = 'jpeg' + if image.mode not in ("RGBA", "RGB", "L"): + image = image.convert("RGBA") + if format.lower() not in ("jpg", "jpeg", "png"): + format = "jpeg" image.save(buf, format, quality=90) raw_data = buf.getvalue() buf.close() @@ -143,19 +143,18 @@ def generate(self, storage, original, size, miniature): class CropscaleThumbnailer(Thumbnailer): - THUMBNAIL_SIZE_RE = re.compile( - r'^(?P\d+)x(?P\d+)(-(?P\d+)x(?P\d+))?$') - MARKER = '_cropscale_' + THUMBNAIL_SIZE_RE = re.compile(r"^(?P\d+)x(?P\d+)(-(?P\d+)x(?P\d+))?$") + MARKER = "_cropscale_" def generate(self, storage, original, size, miniature): with storage.open(original) as original_handle: with BytesIO(original_handle.read()) as original_bytes: image = Image.open(original_bytes) - w, h = int(size['w']), int(size['h']) + w, h = int(size["w"]), int(size["h"]) - if size['x'] and size['y']: - x, y = int(size['x']), int(size['y']) + if size["x"] and size["y"]: + x, y = int(size["x"]), int(size["y"]) else: x, y = 50, 50 @@ -176,18 +175,21 @@ def generate(self, storage, original, size, miniature): y_offset = int(float(src_height - crop_height) * y / 100) format = image.format # Save format for the save() call later - image = image.crop(( - x_offset, - y_offset, - x_offset + int(crop_width), - y_offset + int(crop_height))) + image = image.crop( + ( + x_offset, + y_offset, + x_offset + int(crop_width), + y_offset + int(crop_height), + ) + ) image = image.resize((dst_width, dst_height), Image.ANTIALIAS) buf = BytesIO() - if image.mode not in ('RGBA', 'RGB', 'L'): - image = image.convert('RGBA') - if format.lower() not in ('jpg', 'jpeg', 'png'): - format = 'jpeg' + if image.mode not in ("RGBA", "RGB", "L"): + image = image.convert("RGBA") + if format.lower() not in ("jpg", "jpeg", "png"): + format = "jpeg" image.save(buf, format, quality=90) raw_data = buf.getvalue() buf.close() @@ -199,7 +201,7 @@ def generate(self, storage, original, size, miniature): @register.filter -def thumbnail(filename, size='200x200'): +def thumbnail(filename, size="200x200"): """ Creates a thumbnail from the image passed, returning its path:: @@ -224,7 +226,7 @@ def thumbnail(filename, size='200x200'): @register.filter -def cropscale(filename, size='200x200'): +def cropscale(filename, size="200x200"): """ Scales the image down and crops it so that its size equals exactly the size passed (as long as the initial image is bigger than the specification). diff --git a/feincms/templatetags/fragment_tags.py b/feincms/templatetags/fragment_tags.py index 5c5e7098b..fd8fc4904 100644 --- a/feincms/templatetags/fragment_tags.py +++ b/feincms/templatetags/fragment_tags.py @@ -7,7 +7,7 @@ class FragmentNode(template.Node): - def __init__(self, nodelist, request, identifier, mode='append'): + def __init__(self, nodelist, request, identifier, mode="append"): self.nodelist = nodelist self.request_var = template.Variable(request) self.identifier_var = template.Variable(identifier) @@ -18,19 +18,19 @@ def render(self, context): identifier = self.identifier_var.resolve(context) rendered = self.nodelist.render(context) - if not hasattr(request, '_feincms_fragments'): + if not hasattr(request, "_feincms_fragments"): request._feincms_fragments = {} - old = request._feincms_fragments.get(identifier, '') + old = request._feincms_fragments.get(identifier, "") - if self.mode == 'prepend': + if self.mode == "prepend": request._feincms_fragments[identifier] = rendered + old - elif self.mode == 'replace': + elif self.mode == "replace": request._feincms_fragments[identifier] = rendered else: # append request._feincms_fragments[identifier] = old + rendered - return '' + return "" @register.tag @@ -50,7 +50,7 @@ def fragment(parser, token): {% endfragment %} """ - nodelist = parser.parse(('endfragment'),) + nodelist = parser.parse(("endfragment")) parser.delete_first_token() return FragmentNode(nodelist, *token.contents.split()[1:]) @@ -69,11 +69,11 @@ def render(self, context): try: value = request._feincms_fragments[fragment] except (AttributeError, KeyError): - value = '' + value = "" if self.as_var: context[self.as_var] = value - return '' + return "" return value @@ -95,10 +95,11 @@ def get_fragment(parser, token): if len(fragments) == 3: return GetFragmentNode(fragments[1], fragments[2]) - elif len(fragments) == 5 and fragments[3] == 'as': + elif len(fragments) == 5 and fragments[3] == "as": return GetFragmentNode(fragments[1], fragments[2], fragments[4]) raise template.TemplateSyntaxError( - 'Invalid syntax for get_fragment: %s' % token.contents) + "Invalid syntax for get_fragment: %s" % token.contents + ) @register.filter @@ -108,4 +109,4 @@ def has_fragment(request, identifier): {% if request|has_fragment:"title" %} ... {% endif %} """ - return getattr(request, '_feincms_fragments', {}).get(identifier) + return getattr(request, "_feincms_fragments", {}).get(identifier) diff --git a/feincms/translations.py b/feincms/translations.py index eaab23da9..68e3a2cf8 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -47,6 +47,7 @@ class _NoTranslation(object): """Simple marker for when no translations exist for a certain object Only used for caching.""" + pass @@ -65,7 +66,7 @@ def short_language_code(code=None): if code is None: code = translation.get_language() - pos = code.find('-') + pos = code.find("-") if pos > -1: return code[:pos] return code @@ -91,6 +92,7 @@ def lookup_translations(language_code=None): The current language is used if ``language_code`` isn't specified. """ + def _transform(qs): lang_ = language_code if language_code else translation.get_language() @@ -112,22 +114,16 @@ def _transform(qs): if not instance_dict: return - candidates = list( - instance_dict.values() - )[0].translations.model._default_manager.all() + candidates = list(instance_dict.values())[ + 0 + ].translations.model._default_manager.all() if instance_dict: - _process(candidates, instance_dict, lang_, 'iexact') + _process(candidates, instance_dict, lang_, "iexact") if instance_dict: - _process( - candidates, - instance_dict, - settings.LANGUAGE_CODE, - 'istartswith', - ) + _process(candidates, instance_dict, settings.LANGUAGE_CODE, "istartswith") if instance_dict: - for candidate in candidates.filter( - parent__pk__in=instance_dict.keys()): + for candidate in candidates.filter(parent__pk__in=instance_dict.keys()): if candidate.parent_id in instance_dict: _found(instance_dict, candidate) @@ -145,9 +141,9 @@ def _found(instance_dict, candidate): def _process(candidates, instance_dict, lang_, op_): candidates = candidates.filter( Q(parent__pk__in=instance_dict.keys()), - Q(**{'language_code__' + op_: lang_}) | - Q(**{'language_code__' + op_: short_language_code(lang_)}) - ).order_by('-language_code') + Q(**{"language_code__" + op_: lang_}) + | Q(**{"language_code__" + op_: short_language_code(lang_)}), + ).order_by("-language_code") for candidate in candidates: # The candidate's parent might already have a translation by now @@ -169,9 +165,9 @@ def only_language(self, language=short_language_code): Uses the currently active language by default. """ - return self.filter(translations__language_code=( - language() if callable(language) else language - )) + return self.filter( + translations__language_code=(language() if callable(language) else language) + ) @python_2_unicode_compatible @@ -183,16 +179,19 @@ class TranslatedObjectMixin(object): def _get_translation_object(self, queryset, language_code): try: return queryset.filter( - Q(language_code__iexact=language_code) | - Q(language_code__iexact=short_language_code(language_code)) - ).order_by('-language_code')[0] + Q(language_code__iexact=language_code) + | Q(language_code__iexact=short_language_code(language_code)) + ).order_by("-language_code")[0] except IndexError: try: return queryset.filter( - Q(language_code__istartswith=settings.LANGUAGE_CODE) | - Q(language_code__istartswith=short_language_code( - settings.LANGUAGE_CODE)) - ).order_by('-language_code')[0] + Q(language_code__istartswith=settings.LANGUAGE_CODE) + | Q( + language_code__istartswith=short_language_code( + settings.LANGUAGE_CODE + ) + ) + ).order_by("-language_code")[0] except IndexError: try: return queryset.all()[0] @@ -204,15 +203,8 @@ def get_translation_cache_key(self, language_code=None): can purge on-demand""" if not language_code: language_code = translation.get_language() - return ( - ('FEINCMS:%d:XLATION:' % getattr(settings, 'SITE_ID', 0)) + - '-'.join( - ['%s' % s for s in ( - self._meta.db_table, - self.id, - language_code, - )] - ) + return ("FEINCMS:%d:XLATION:" % getattr(settings, "SITE_ID", 0)) + "-".join( + ["%s" % s for s in (self._meta.db_table, self.id, language_code)] ) def get_translation(self, language_code=None): @@ -226,7 +218,8 @@ def get_translation(self, language_code=None): if trans is None: try: trans = self._get_translation_object( - self.translations.all(), language_code) + self.translations.all(), language_code + ) except ObjectDoesNotExist: trans = _NoTranslation cache.set(key, trans) @@ -240,13 +233,13 @@ def get_translation(self, language_code=None): @property def translation(self): - if not hasattr(self, '_cached_translation'): + if not hasattr(self, "_cached_translation"): self._cached_translation = self.get_translation() return self._cached_translation @property def available_translations(self): - return self.translations.values_list('language_code', flat=True) + return self.translations.values_list("language_code", flat=True) def __str__(self): try: @@ -255,7 +248,7 @@ def __str__(self): return self.__class__.__name__ if translation: - return '%s' % translation + return "%s" % translation return self.__class__.__name__ @@ -280,14 +273,18 @@ def Translation(model): class Inner(models.Model): parent = models.ForeignKey( - model, related_name='translations', on_delete=models.CASCADE) + model, related_name="translations", on_delete=models.CASCADE + ) language_code = models.CharField( - _('language'), max_length=10, - choices=settings.LANGUAGES, default=settings.LANGUAGES[0][0], - editable=len(settings.LANGUAGES) > 1) + _("language"), + max_length=10, + choices=settings.LANGUAGES, + default=settings.LANGUAGES[0][0], + editable=len(settings.LANGUAGES) > 1, + ) class Meta: - unique_together = ('parent', 'language_code') + unique_together = ("parent", "language_code") # (beware the above will not be inherited automatically if you # provide a Meta class within your translation subclass) abstract = True @@ -298,11 +295,13 @@ def short_language_code(self): def save(self, *args, **kwargs): super(Inner, self).save(*args, **kwargs) self.parent.purge_translation_cache() + save.alters_data = True def delete(self, *args, **kwargs): super(Inner, self).delete(*args, **kwargs) self.parent.purge_translation_cache() + delete.alters_data = True return Inner @@ -322,8 +321,7 @@ def admin_translationinline(model, inline_class=admin.StackedInline, **kwargs): ) """ - kwargs['extra'] = 1 - kwargs['max_num'] = len(settings.LANGUAGES) - kwargs['model'] = model - return type( - str(model.__class__.__name__ + 'Inline'), (inline_class,), kwargs) + kwargs["extra"] = 1 + kwargs["max_num"] = len(settings.LANGUAGES) + kwargs["model"] = model + return type(str(model.__class__.__name__ + "Inline"), (inline_class,), kwargs) diff --git a/feincms/urls.py b/feincms/urls.py index 357f72e9b..bb7bd851b 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -8,6 +8,6 @@ handler = Handler.as_view() urlpatterns = [ - url(r'^$', handler, name='feincms_home'), - url(r'^(.*)/$', handler, name='feincms_handler'), + url(r"^$", handler, name="feincms_home"), + url(r"^(.*)/$", handler, name="feincms_handler"), ] diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index aef8b207b..75397f11f 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -27,8 +27,8 @@ def get_object(path, fail_silently=False): return import_module(path) except ImportError: try: - dot = path.rindex('.') - mod, fn = path[:dot], path[dot + 1:] + dot = path.rindex(".") + mod, fn = path[:dot], path[dot + 1 :] return getattr(import_module(mod), fn) except (AttributeError, ImportError): @@ -60,8 +60,7 @@ def get_model_instance(app_label, model_name, pk): # ------------------------------------------------------------------------ -REDIRECT_TO_RE = re.compile( - r'^(?P\w+).(?P\w+):(?P\d+)$') +REDIRECT_TO_RE = re.compile(r"^(?P\w+).(?P\w+):(?P\d+)$") def match_model_string(s): @@ -77,7 +76,7 @@ def match_model_string(s): if not match: return None matches = match.groupdict() - return (matches['app_label'], matches['model_name'], int(matches['pk'])) + return (matches["app_label"], matches["model_name"], int(matches["pk"])) # ------------------------------------------------------------------------ @@ -89,14 +88,17 @@ def copy_model_instance(obj, exclude=None): exclude = exclude or () initial = dict( - (f.name, getattr(obj, f.name)) for f in obj._meta.fields - if not isinstance(f, AutoField) and f.name not in exclude and - f not in obj._meta.parents.values()) + (f.name, getattr(obj, f.name)) + for f in obj._meta.fields + if not isinstance(f, AutoField) + and f.name not in exclude + and f not in obj._meta.parents.values() + ) return obj.__class__(**initial) # ------------------------------------------------------------------------ -def shorten_string(str, max_length=50, ellipsis=' … '): +def shorten_string(str, max_length=50, ellipsis=" … "): """ Shorten a string for display, truncate it intelligently when too long. Try to cut it in 2/3 + ellipsis + 1/3 of the original title. Also try to @@ -105,14 +107,14 @@ def shorten_string(str, max_length=50, ellipsis=' … '): if len(str) >= max_length: first_part = int(max_length * 0.6) - next_space = str[first_part:(max_length // 2 - first_part)].find(' ') - if (next_space >= 0 and - first_part + next_space + len(ellipsis) < max_length): + next_space = str[first_part : (max_length // 2 - first_part)].find(" ") + if next_space >= 0 and first_part + next_space + len(ellipsis) < max_length: first_part += next_space return ( - str[:first_part] + - ellipsis + - str[-(max_length - first_part - len(ellipsis)):]) + str[:first_part] + + ellipsis + + str[-(max_length - first_part - len(ellipsis)) :] + ) return str @@ -120,31 +122,22 @@ def shorten_string(str, max_length=50, ellipsis=' … '): def get_singleton(template_key, cls=None, raise_exception=True): cls = cls or settings.FEINCMS_DEFAULT_PAGE_MODEL try: - model = apps.get_model(*cls.split('.')) + model = apps.get_model(*cls.split(".")) if not model: raise ImproperlyConfigured('Cannot load model "%s"' % cls) try: assert model._feincms_templates[template_key].singleton except AttributeError as e: raise ImproperlyConfigured( - '%r does not seem to be a valid FeinCMS base class (%r)' % ( - model, - e, - ) + "%r does not seem to be a valid FeinCMS base class (%r)" % (model, e) ) except KeyError: raise ImproperlyConfigured( - '%r is not a registered template for %r!' % ( - template_key, - model, - ) + "%r is not a registered template for %r!" % (template_key, model) ) except AssertionError: raise ImproperlyConfigured( - '%r is not a *singleton* template for %r!' % ( - template_key, - model, - ) + "%r is not a *singleton* template for %r!" % (template_key, model) ) try: return model._default_manager.get(template_key=template_key) @@ -161,4 +154,4 @@ def get_singleton(template_key, cls=None, raise_exception=True): def get_singleton_url(template_key, cls=None, raise_exception=True): obj = get_singleton(template_key, cls, raise_exception) - return obj.get_absolute_url() if obj else '#broken-link' + return obj.get_absolute_url() if obj else "#broken-link" diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index e7110a7d1..7ded0c45b 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -91,7 +91,7 @@ class TransformQuerySet(models.query.QuerySet): def __init__(self, *args, **kwargs): super(TransformQuerySet, self).__init__(*args, **kwargs) self._transform_fns = [] - self._orig_iterable_class = getattr(self, '_iterable_class', None) + self._orig_iterable_class = getattr(self, "_iterable_class", None) def _clone(self, *args, **kwargs): c = super(TransformQuerySet, self)._clone(*args, **kwargs) @@ -104,13 +104,16 @@ def transform(self, *fn): return c if django.VERSION < (1, 11): + def iterator(self): result_iter = super(TransformQuerySet, self).iterator() if not self._transform_fns: return result_iter - if getattr(self, '_iterable_class', None) != self._orig_iterable_class: # noqa + if ( + getattr(self, "_iterable_class", None) != self._orig_iterable_class + ): # noqa # Do not process the result of values() and values_list() return result_iter @@ -120,17 +123,21 @@ def iterator(self): return iter(results) else: + def _fetch_all(self): super(TransformQuerySet, self)._fetch_all() - if getattr(self, '_iterable_class', None) == self._orig_iterable_class: # noqa + if ( + getattr(self, "_iterable_class", None) == self._orig_iterable_class + ): # noqa for fn in self._transform_fns: fn(self._result_cache) -if hasattr(models.Manager, 'from_queryset'): +if hasattr(models.Manager, "from_queryset"): TransformManager = models.Manager.from_queryset(TransformQuerySet) else: + class TransformManager(models.Manager): def get_queryset(self): return TransformQuerySet(self.model, using=self._db) diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index 6df5592c5..18258b98d 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -1,4 +1,4 @@ -''' +""" I really hate repeating myself. These are helpers that avoid typing the whole thing over and over when implementing additional template tags @@ -7,7 +7,7 @@ {% tag as var_name %} {% tag of template_var as var_name %} {% tag of template_var as var_name arg1,arg2,kwarg3=4 %} -''' +""" from __future__ import absolute_import, unicode_literals @@ -17,9 +17,9 @@ def _parse_args(argstr, context=None): try: args = {} - for token in argstr.split(','): - if '=' in token: - k, v = token.split('=', 1) + for token in argstr.split(","): + if "=" in token: + k, v = token.split("=", 1) if context: try: args[k] = template.Variable(v).resolve(context) @@ -33,23 +33,21 @@ def _parse_args(argstr, context=None): return args except TypeError: - raise template.TemplateSyntaxError('Malformed arguments') + raise template.TemplateSyntaxError("Malformed arguments") def do_simple_assignment_node_with_var_and_args_helper(cls): def _func(parser, token): try: - tag_name, of_, in_var_name, as_, var_name, args =\ - token.contents.split() + tag_name, of_, in_var_name, as_, var_name, args = token.contents.split() except ValueError: try: - tag_name, of_, in_var_name, as_, var_name =\ - token.contents.split() - args = '' + tag_name, of_, in_var_name, as_, var_name = token.contents.split() + args = "" except ValueError: raise template.TemplateSyntaxError( - 'Invalid syntax for %s node: %s' % ( - cls.__name__, token.contents)) + "Invalid syntax for %s node: %s" % (cls.__name__, token.contents) + ) return cls(tag_name, in_var_name, var_name, args) @@ -69,9 +67,8 @@ def render(self, context): instance = self.in_var.resolve(context) except template.VariableDoesNotExist: context[self.var_name] = [] - return '' + return "" - context[self.var_name] = self.what( - instance, _parse_args(self.args, context)) + context[self.var_name] = self.what(instance, _parse_args(self.args, context)) - return '' + return "" diff --git a/feincms/views/__init__.py b/feincms/views/__init__.py index 416ab850f..014a6adc8 100644 --- a/feincms/views/__init__.py +++ b/feincms/views/__init__.py @@ -15,19 +15,20 @@ class Handler(ContentView): page_model_path = None - context_object_name = 'feincms_page' + context_object_name = "feincms_page" @cached_property def page_model(self): model = self.page_model_path or settings.FEINCMS_DEFAULT_PAGE_MODEL - return apps.get_model(*model.split('.')) + return apps.get_model(*model.split(".")) def get_object(self): path = None if self.args: path = self.args[0] return self.page_model._default_manager.for_request( - self.request, raise404=True, best_match=True, path=path) + self.request, raise404=True, best_match=True, path=path + ) def dispatch(self, request, *args, **kwargs): try: @@ -36,7 +37,9 @@ def dispatch(self, request, *args, **kwargs): if settings.FEINCMS_CMS_404_PAGE is not None: logger.info( "Http404 raised for '%s', attempting redirect to" - " FEINCMS_CMS_404_PAGE", args[0]) + " FEINCMS_CMS_404_PAGE", + args[0], + ) try: # Fudge environment so that we end up resolving the right # page. @@ -45,12 +48,12 @@ def dispatch(self, request, *args, **kwargs): # page url. # Also clear out the _feincms_page attribute which caches # page lookups (and would just re-raise a 404). - request.path = request.path_info =\ - settings.FEINCMS_CMS_404_PAGE - if hasattr(request, '_feincms_page'): - delattr(request, '_feincms_page') + request.path = request.path_info = settings.FEINCMS_CMS_404_PAGE + if hasattr(request, "_feincms_page"): + delattr(request, "_feincms_page") response = super(Handler, self).dispatch( - request, settings.FEINCMS_CMS_404_PAGE, **kwargs) + request, settings.FEINCMS_CMS_404_PAGE, **kwargs + ) # Only set status if we actually have a page. If we get for # example a redirect, overwriting would yield a blank page if response.status_code == 200: @@ -58,9 +61,9 @@ def dispatch(self, request, *args, **kwargs): return response except Http404: logger.error( - "Http404 raised while resolving" - " FEINCMS_CMS_404_PAGE=%s", - settings.FEINCMS_CMS_404_PAGE) + "Http404 raised while resolving" " FEINCMS_CMS_404_PAGE=%s", + settings.FEINCMS_CMS_404_PAGE, + ) raise e else: raise diff --git a/feincms/views/decorators.py b/feincms/views/decorators.py index 2fab30127..656e50800 100644 --- a/feincms/views/decorators.py +++ b/feincms/views/decorators.py @@ -6,5 +6,7 @@ from feincms.apps import * warnings.warn( - 'Import ApplicationContent and friends from feincms.content.application.models', - DeprecationWarning, stacklevel=2) + "Import ApplicationContent and friends from feincms.content.application.models", + DeprecationWarning, + stacklevel=2, +) diff --git a/setup.cfg b/setup.cfg index cc4bd75fa..948dea0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,8 @@ [flake8] -exclude=venv,.tox,build,docs,migrations +exclude=venv,build,docs,.tox,migrations +ignore=E203,W503 +max-line-length=88 +# max-complexity=10 [wheel] universal = 1 diff --git a/setup.py b/setup.py index 2f1156902..a9fdce423 100755 --- a/setup.py +++ b/setup.py @@ -7,53 +7,51 @@ def read(filename): path = os.path.join(os.path.dirname(__file__), filename) - with open(path, encoding='utf-8') as handle: + with open(path, encoding="utf-8") as handle: return handle.read() -version = __import__('feincms').__version__ -devstatus = 'Development Status :: 5 - Production/Stable' -if '.dev' in version: - devstatus = 'Development Status :: 3 - Alpha' -elif '.pre' in version: - devstatus = 'Development Status :: 4 - Beta' +version = __import__("feincms").__version__ +devstatus = "Development Status :: 5 - Production/Stable" +if ".dev" in version: + devstatus = "Development Status :: 3 - Alpha" +elif ".pre" in version: + devstatus = "Development Status :: 4 - Beta" setup( - name='FeinCMS', + name="FeinCMS", version=version, - description='Django-based Page CMS and CMS building toolkit.', - long_description=read('README.rst'), - author='Matthias Kestenholz', - author_email='mk@feinheit.ch', - url='http://github.com/feincms/feincms/', - license='BSD License', - platforms=['OS Independent'], - packages=find_packages( - exclude=['tests'] - ), + description="Django-based Page CMS and CMS building toolkit.", + long_description=read("README.rst"), + author="Matthias Kestenholz", + author_email="mk@feinheit.ch", + url="http://github.com/feincms/feincms/", + license="BSD License", + platforms=["OS Independent"], + packages=find_packages(exclude=["tests"]), include_package_data=True, install_requires=[ - 'Django>=1.7', - 'django-mptt>=0.7.1', - 'Pillow>=2.0.0', - 'pytz>=2014.10', + "Django>=1.7", + "django-mptt>=0.7.1", + "Pillow>=2.0.0", + "pytz>=2014.10", ], classifiers=[ devstatus, - 'Environment :: Web Environment', - 'Framework :: Django', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - 'Topic :: Software Development', - 'Topic :: Software Development :: Libraries :: Application Frameworks', + "Environment :: Web Environment", + "Framework :: Django", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries :: Application Frameworks", ], zip_safe=False, ) diff --git a/tests/manage.py b/tests/manage.py index 817e86b82..e20cc5e6d 100755 --- a/tests/manage.py +++ b/tests/manage.py @@ -5,8 +5,7 @@ if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings") - sys.path.insert( - 0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from django.core.management import execute_from_command_line diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index 5a1ba3cb4..92a58d13f 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -13,57 +13,54 @@ def module_root(request): - return HttpResponse('module_root') + return HttpResponse("module_root") def args_test(request, kwarg1, kwarg2): - return HttpResponse('%s-%s' % (kwarg1, kwarg2)) + return HttpResponse("%s-%s" % (kwarg1, kwarg2)) def full_reverse_test(request): - return render_to_string('full_reverse_test.html', {}) + return render_to_string("full_reverse_test.html", {}) def alias_reverse_test(request): - return render_to_string('alias_reverse_test.html', {}) + return render_to_string("alias_reverse_test.html", {}) def fragment(request): - return render_to_string('fragment.html', {'request': request}) + return render_to_string("fragment.html", {"request": request}) def redirect(request): - return HttpResponseRedirect(request.build_absolute_uri('../')) + return HttpResponseRedirect(request.build_absolute_uri("../")) def response(request): - return HttpResponse('Anything') + return HttpResponse("Anything") def inheritance20(request): - return 'inheritance20.html', {'from_appcontent': 42} + return "inheritance20.html", {"from_appcontent": 42} @unpack def inheritance20_unpack(request): - response = TemplateResponse( - request, - 'inheritance20.html', - {'from_appcontent': 43}) - response['Cache-Control'] = 'yabba dabba' + response = TemplateResponse(request, "inheritance20.html", {"from_appcontent": 43}) + response["Cache-Control"] = "yabba dabba" return response urlpatterns = [ - url(r'^$', module_root, name='ac_module_root'), - url(r'^args_test/([^/]+)/([^/]+)/$', args_test, name='ac_args_test'), - url(r'^kwargs_test/(?P[^/]+)/(?P[^/]+)/$', args_test), - url(r'^full_reverse_test/$', full_reverse_test), - url(r'^alias_reverse_test/$', alias_reverse_test), - url(r'^fragment/$', fragment), - url(r'^redirect/$', redirect), - url(r'^response/$', response), - url(r'^response_decorated/$', standalone(response)), - url(r'^inheritance20/$', inheritance20), - url(r'^inheritance20_unpack/$', inheritance20_unpack), + url(r"^$", module_root, name="ac_module_root"), + url(r"^args_test/([^/]+)/([^/]+)/$", args_test, name="ac_args_test"), + url(r"^kwargs_test/(?P[^/]+)/(?P[^/]+)/$", args_test), + url(r"^full_reverse_test/$", full_reverse_test), + url(r"^alias_reverse_test/$", alias_reverse_test), + url(r"^fragment/$", fragment), + url(r"^redirect/$", redirect), + url(r"^response/$", response), + url(r"^response_decorated/$", standalone(response)), + url(r"^inheritance20/$", inheritance20), + url(r"^inheritance20_unpack/$", inheritance20_unpack), ] diff --git a/tests/testapp/context_processors.py b/tests/testapp/context_processors.py index 7d0253c20..c477b6489 100644 --- a/tests/testapp/context_processors.py +++ b/tests/testapp/context_processors.py @@ -1,2 +1,2 @@ def test_context(request): - return {'THE_ANSWER': 42} + return {"THE_ANSWER": 42} diff --git a/tests/testapp/migrations/0001_initial.py b/tests/testapp/migrations/0001_initial.py index a851c06a8..dbd8263e1 100644 --- a/tests/testapp/migrations/0001_initial.py +++ b/tests/testapp/migrations/0001_initial.py @@ -9,77 +9,123 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Category', + name="Category", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=20)), - ('slug', models.SlugField()), - ('lft', models.PositiveIntegerField(db_index=True, editable=False)), - ('rght', models.PositiveIntegerField(db_index=True, editable=False)), - ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), - ('level', models.PositiveIntegerField(db_index=True, editable=False)), - ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='testapp.Category')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=20)), + ("slug", models.SlugField()), + ("lft", models.PositiveIntegerField(db_index=True, editable=False)), + ("rght", models.PositiveIntegerField(db_index=True, editable=False)), + ("tree_id", models.PositiveIntegerField(db_index=True, editable=False)), + ("level", models.PositiveIntegerField(db_index=True, editable=False)), + ( + "parent", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="children", + to="testapp.Category", + ), + ), ], options={ - 'verbose_name': 'category', - 'verbose_name_plural': 'categories', - 'ordering': ['tree_id', 'lft'], + "verbose_name": "category", + "verbose_name_plural": "categories", + "ordering": ["tree_id", "lft"], }, ), migrations.CreateModel( - name='CustomContentType', + name="CustomContentType", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('region', models.CharField(max_length=255)), - ('ordering', models.IntegerField(default=0, verbose_name='ordering')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("region", models.CharField(max_length=255)), + ("ordering", models.IntegerField(default=0, verbose_name="ordering")), ], options={ - 'verbose_name': 'custom content type', - 'verbose_name_plural': 'custom content types', - 'db_table': 'testapp_mymodel_customcontenttype', - 'ordering': ['ordering'], - 'permissions': [], - 'abstract': False, + "verbose_name": "custom content type", + "verbose_name_plural": "custom content types", + "db_table": "testapp_mymodel_customcontenttype", + "ordering": ["ordering"], + "permissions": [], + "abstract": False, }, ), migrations.CreateModel( - name='ExampleCMSBase', + name="ExampleCMSBase", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], - options={ - 'abstract': False, - }, + options={"abstract": False}, bases=(models.Model, feincms.extensions.base.ExtensionsMixin), ), migrations.CreateModel( - name='ExampleCMSBase2', + name="ExampleCMSBase2", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], - options={ - 'abstract': False, - }, + options={"abstract": False}, bases=(models.Model, feincms.extensions.base.ExtensionsMixin), ), migrations.CreateModel( - name='MyModel', + name="MyModel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], - options={ - 'abstract': False, - }, + options={"abstract": False}, bases=(models.Model, feincms.extensions.base.ExtensionsMixin), ), migrations.AddField( - model_name='customcontenttype', - name='parent', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customcontenttype_set', to='testapp.MyModel'), + model_name="customcontenttype", + name="parent", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="customcontenttype_set", + to="testapp.MyModel", + ), ), ] diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 05328489a..c51402d95 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -17,69 +17,69 @@ from .content import CustomContentType -Page.register_templates({ - 'key': 'base', - 'title': 'Base Template', - 'path': 'base.html', - 'regions': ( - ('main', 'Main region'), - ('sidebar', 'Sidebar', 'inherited'), - ), -}) +Page.register_templates( + { + "key": "base", + "title": "Base Template", + "path": "base.html", + "regions": (("main", "Main region"), ("sidebar", "Sidebar", "inherited")), + } +) Page.create_content_type(RawContent) Page.create_content_type( - MediaFileContent, - TYPE_CHOICES=( - ('default', 'Default position'), - ) + MediaFileContent, TYPE_CHOICES=(("default", "Default position"),) +) +Page.create_content_type( + TemplateContent, TEMPLATES=[("templatecontent_1.html", "template 1")] ) -Page.create_content_type(TemplateContent, TEMPLATES=[ - ('templatecontent_1.html', 'template 1'), -]) Page.register_request_processor(processors.etag_request_processor) Page.register_response_processor(processors.etag_response_processor) -Page.register_response_processor( - processors.debug_sql_queries_response_processor()) +Page.register_response_processor(processors.debug_sql_queries_response_processor()) def get_admin_fields(form, *args, **kwargs): return { - 'exclusive_subpages': forms.BooleanField( - label=capfirst(_('exclusive subpages')), + "exclusive_subpages": forms.BooleanField( + label=capfirst(_("exclusive subpages")), required=False, - initial=form.instance.parameters.get('exclusive_subpages', False), + initial=form.instance.parameters.get("exclusive_subpages", False), help_text=_( - 'Exclude everything other than the application\'s content' - ' when rendering subpages.'), + "Exclude everything other than the application's content" + " when rendering subpages." + ), ), - 'custom_field': forms.CharField(), + "custom_field": forms.CharField(), } Page.create_content_type( ApplicationContent, APPLICATIONS=( - ('whatever', 'Test Urls', { - 'admin_fields': get_admin_fields, - 'urls': 'testapp.applicationcontent_urls', - }), - ) + ( + "whatever", + "Test Urls", + { + "admin_fields": get_admin_fields, + "urls": "testapp.applicationcontent_urls", + }, + ), + ), ) Page.register_extensions( - 'feincms.module.page.extensions.navigation', - 'feincms.module.page.extensions.sites', - 'feincms.extensions.translations', - 'feincms.extensions.datepublisher', - 'feincms.extensions.translations', - 'feincms.extensions.ct_tracker', - 'feincms.extensions.seo', - 'feincms.extensions.changedate', - 'feincms.extensions.seo', # duplicate - 'feincms.module.page.extensions.navigation', - 'feincms.module.page.extensions.symlinks', - 'feincms.module.page.extensions.titles', - 'feincms.module.page.extensions.navigationgroups', + "feincms.module.page.extensions.navigation", + "feincms.module.page.extensions.sites", + "feincms.extensions.translations", + "feincms.extensions.datepublisher", + "feincms.extensions.translations", + "feincms.extensions.ct_tracker", + "feincms.extensions.seo", + "feincms.extensions.changedate", + "feincms.extensions.seo", # duplicate + "feincms.module.page.extensions.navigation", + "feincms.module.page.extensions.symlinks", + "feincms.module.page.extensions.titles", + "feincms.module.page.extensions.navigationgroups", ) @@ -88,13 +88,13 @@ class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() parent = models.ForeignKey( - 'self', blank=True, null=True, related_name='children', - on_delete=models.CASCADE) + "self", blank=True, null=True, related_name="children", on_delete=models.CASCADE + ) class Meta: - ordering = ['tree_id', 'lft'] - verbose_name = 'category' - verbose_name_plural = 'categories' + ordering = ["tree_id", "lft"] + verbose_name = "category" + verbose_name_plural = "categories" def __str__(self): return self.name @@ -105,24 +105,24 @@ class ExampleCMSBase(Base): ExampleCMSBase.register_regions( - ('region', 'region title'), - ('region2', 'region2 title')) + ("region", "region title"), ("region2", "region2 title") +) class ExampleCMSBase2(Base): - pass + pass ExampleCMSBase2.register_regions( - ('region', 'region title'), - ('region2', 'region2 title')) + ("region", "region title"), ("region2", "region2 title") +) class MyModel(create_base_model()): pass -MyModel.register_regions(('main', 'Main region')) +MyModel.register_regions(("main", "Main region")) unchanged = CustomContentType diff --git a/tests/testapp/navigation_extensions.py b/tests/testapp/navigation_extensions.py index bbd691839..6400375fb 100644 --- a/tests/testapp/navigation_extensions.py +++ b/tests/testapp/navigation_extensions.py @@ -1,12 +1,11 @@ from __future__ import absolute_import, unicode_literals -from feincms.module.page.extensions.navigation import ( - NavigationExtension, PagePretender) +from feincms.module.page.extensions.navigation import NavigationExtension, PagePretender class PassthroughExtension(NavigationExtension): # See PagesTestCase.test_23_navigation_extension - name = 'passthrough extension' + name = "passthrough extension" def children(self, page, **kwargs): for p in page.children.in_navigation(): @@ -14,7 +13,7 @@ def children(self, page, **kwargs): class PretenderExtension(NavigationExtension): - name = 'pretender extension' + name = "pretender extension" def children(self, page, **kwargs): - return [PagePretender(title='blabla', url='/asdsa/')] + return [PagePretender(title="blabla", url="/asdsa/")] diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 560875262..4df48ea5b 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -5,73 +5,68 @@ SITE_ID = 1 -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': ':memory:', - } -} +DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}} INSTALLED_APPS = [ - 'django.contrib.auth', - 'django.contrib.admin', - 'django.contrib.contenttypes', - 'django.contrib.messages', - 'django.contrib.sessions', - 'django.contrib.sitemaps', - 'django.contrib.sites', - 'django.contrib.staticfiles', - 'feincms', - 'feincms.module.medialibrary', - 'feincms.module.page', - 'mptt', - 'testapp', + "django.contrib.auth", + "django.contrib.admin", + "django.contrib.contenttypes", + "django.contrib.messages", + "django.contrib.sessions", + "django.contrib.sitemaps", + "django.contrib.sites", + "django.contrib.staticfiles", + "feincms", + "feincms.module.medialibrary", + "feincms.module.page", + "mptt", + "testapp", ] -MEDIA_URL = '/media/' -STATIC_URL = '/static/' +MEDIA_URL = "/media/" +STATIC_URL = "/static/" BASEDIR = os.path.dirname(__file__) -MEDIA_ROOT = os.path.join(BASEDIR, 'media/') -STATIC_ROOT = os.path.join(BASEDIR, 'static/') -SECRET_KEY = 'supersikret' +MEDIA_ROOT = os.path.join(BASEDIR, "media/") +STATIC_ROOT = os.path.join(BASEDIR, "static/") +SECRET_KEY = "supersikret" USE_TZ = True -ROOT_URLCONF = 'testapp.urls' -LANGUAGES = (('en', 'English'), ('de', 'German')) +ROOT_URLCONF = "testapp.urls" +LANGUAGES = (("en", "English"), ("de", "German")) TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', - 'django.core.context_processors.static', + "django.contrib.auth.context_processors.auth", + "django.core.context_processors.debug", + "django.core.context_processors.i18n", + "django.core.context_processors.media", + "django.core.context_processors.static", # request context processor is needed - 'django.core.context_processors.request', - 'testapp.context_processors.test_context', + "django.core.context_processors.request", + "testapp.context_processors.test_context", ) TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'testapp.context_processors.test_context', - ], + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "testapp.context_processors.test_context", + ] }, - }, + } ] MIDDLEWARE = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.locale.LocaleMiddleware' + "django.middleware.common.CommonMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.locale.LocaleMiddleware", ) if django.VERSION < (1, 11): @@ -79,10 +74,12 @@ if (2,) <= django.VERSION < (2, 1): from django.utils import deprecation + # Anything to make mptt.templatetags.mptt_admin importable deprecation.RemovedInDjango20Warning = deprecation.RemovedInDjango21Warning elif django.VERSION >= (2,): from django.utils import deprecation + # Anything to make mptt.templatetags.mptt_admin importable deprecation.RemovedInDjango20Warning = deprecation.RemovedInDjango30Warning diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index 557b65125..1e818ed72 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -21,13 +21,13 @@ from django.utils.unittest import skipIf skipUnlessLegacy = skipIf( - django.VERSION >= (1, 8), - "Legacy tests only necessary in Django < 1.8") + django.VERSION >= (1, 8), "Legacy tests only necessary in Django < 1.8" +) # ------------------------------------------------------------------------ class SubRawContent(RawContent): - title = models.CharField('title', max_length=100, blank=True) + title = models.CharField("title", max_length=100, blank=True) class Meta: abstract = True @@ -37,7 +37,7 @@ class CMSBaseTest(TestCase): def test_01_simple_content_type_creation(self): self.assertEqual(ExampleCMSBase.content_type_for(RawContent), None) - ExampleCMSBase.create_content_type(RawContent, regions=('main2',)) + ExampleCMSBase.create_content_type(RawContent, regions=("main2",)) ExampleCMSBase.create_content_type(RichTextContent) # content_type_for should return None if it does not have a subclass @@ -45,8 +45,9 @@ def test_01_simple_content_type_creation(self): self.assertEqual(ExampleCMSBase.content_type_for(Empty), None) self.assertTrue( - 'rawcontent' not in dict( - ExampleCMSBase.template.regions[0].content_types).keys()) + "rawcontent" + not in dict(ExampleCMSBase.template.regions[0].content_types).keys() + ) def test_04_mediafilecontent_creation(self): # the medialibrary needs to be enabled, otherwise this test fails @@ -54,7 +55,8 @@ def test_04_mediafilecontent_creation(self): # no TYPE_CHOICES, should raise self.assertRaises( ImproperlyConfigured, - lambda: ExampleCMSBase.create_content_type(MediaFileContent)) + lambda: ExampleCMSBase.create_content_type(MediaFileContent), + ) def test_05_non_abstract_content_type(self): # Should not be able to create a content type from a non-abstract base @@ -64,7 +66,8 @@ class TestContentType(models.Model): self.assertRaises( ImproperlyConfigured, - lambda: ExampleCMSBase.create_content_type(TestContentType)) + lambda: ExampleCMSBase.create_content_type(TestContentType), + ) def test_07_default_render_method(self): class SomethingElse(models.Model): @@ -72,29 +75,23 @@ class Meta: abstract = True def render_region(self): - return 'hello' + return "hello" type = ExampleCMSBase.create_content_type(SomethingElse) obj = type() self.assertRaises(NotImplementedError, lambda: obj.render()) - obj.region = 'region' - self.assertEqual(obj.render(), 'hello') + obj.region = "region" + self.assertEqual(obj.render(), "hello") def test_08_creating_two_content_types_in_same_application(self): ExampleCMSBase.create_content_type(RawContent) ct = ExampleCMSBase.content_type_for(RawContent) - self.assertEqual( - ct._meta.db_table, - 'testapp_examplecmsbase_rawcontent') + self.assertEqual(ct._meta.db_table, "testapp_examplecmsbase_rawcontent") - ExampleCMSBase2.create_content_type( - RawContent, - class_name='RawContent2') + ExampleCMSBase2.create_content_type(RawContent, class_name="RawContent2") ct2 = ExampleCMSBase2.content_type_for(RawContent) - self.assertEqual( - ct2._meta.db_table, - 'testapp_examplecmsbase2_rawcontent2') + self.assertEqual(ct2._meta.db_table, "testapp_examplecmsbase2_rawcontent2") @skipUnlessLegacy def test_09_related_objects_cache(self): @@ -111,33 +108,31 @@ def test_09_related_objects_cache(self): It also fails on Django 1.7 since the introduction of django.apps """ + class Attachment(models.Model): - base = models.ForeignKey( - ExampleCMSBase, - related_name='test_related_name') + base = models.ForeignKey(ExampleCMSBase, related_name="test_related_name") # See issue #323 on Github. ExampleCMSBase._meta._fill_related_objects_cache() related_models = map( - lambda x: x.model, ExampleCMSBase._meta.get_all_related_objects()) + lambda x: x.model, ExampleCMSBase._meta.get_all_related_objects() + ) self.assertTrue(Attachment in related_models) - self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) + self.assertTrue(hasattr(ExampleCMSBase, "test_related_name")) # self.assertFalse(hasattr(Attachment, 'anycontents')) class AnyContent(models.Model): - attachment = models.ForeignKey( - Attachment, - related_name='anycontents') + attachment = models.ForeignKey(Attachment, related_name="anycontents") class Meta: abstract = True ExampleCMSBase.create_content_type(AnyContent) - self.assertTrue(hasattr(ExampleCMSBase, 'test_related_name')) - self.assertTrue(hasattr(Attachment, 'anycontents')) + self.assertTrue(hasattr(ExampleCMSBase, "test_related_name")) + self.assertTrue(hasattr(Attachment, "anycontents")) def test_10_content_type_subclasses(self): """ diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index 10c7dc987..4994ceabb 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -15,20 +15,22 @@ class TranslationTestCase(TestCase): def setUp(self): - Page.register_templates({ - 'key': 'base', - 'title': 'Standard template', - 'path': 'feincms_base.html', - 'regions': ( - ('main', 'Main content area'), - ('sidebar', 'Sidebar', 'inherited'), - ), - }) + Page.register_templates( + { + "key": "base", + "title": "Standard template", + "path": "feincms_base.html", + "regions": ( + ("main", "Main content area"), + ("sidebar", "Sidebar", "inherited"), + ), + } + ) self.site_1 = Site.objects.all()[0] # create a bunch of pages - en = self.create_default_page_set(language='en') - de = self.create_default_page_set(language='de', title='Testseite') + en = self.create_default_page_set(language="en") + de = self.create_default_page_set(language="de", title="Testseite") de.translation_of = en de.save() de.parent.translation_of = en.parent @@ -36,36 +38,34 @@ def setUp(self): self.page_de = de.parent self.page_en = en.parent - if hasattr(translation, 'LANGUAGE_SESSION_KEY'): + if hasattr(translation, "LANGUAGE_SESSION_KEY"): self.language_session_key = translation.LANGUAGE_SESSION_KEY else: # Django 1.6 self.language_session_key = django_settings.LANGUAGE_COOKIE_NAME - def create_page(self, title='Test page', parent=None, **kwargs): + def create_page(self, title="Test page", parent=None, **kwargs): defaults = { - 'template_key': 'base', - 'site': self.site_1, - 'in_navigation': False, - 'active': False, + "template_key": "base", + "site": self.site_1, + "in_navigation": False, + "active": False, } defaults.update(kwargs) return Page.objects.create( title=title, - slug=kwargs.get('slug', slugify(title)), + slug=kwargs.get("slug", slugify(title)), parent=parent, - **defaults) + **defaults + ) def create_default_page_set(self, **kwargs): - return self.create_page( - 'Test child page', - parent=self.create_page(**kwargs), - ) + return self.create_page("Test child page", parent=self.create_page(**kwargs)) def testPage(self): page = Page() - self.assertTrue(hasattr(page, 'language')) - self.assertTrue(hasattr(page, 'translation_of')) + self.assertTrue(hasattr(page, "language")) + self.assertTrue(hasattr(page, "translation_of")) self.assertEqual(self.page_de.translation_of, self.page_en) self.assertEqual(self.page_de.original_translation, self.page_en) @@ -75,32 +75,32 @@ def testPage(self): def test_user_has_language_set_with_session(self): factory = RequestFactory() request = factory.get(self.page_en.get_navigation_url()) - setattr(request, 'session', dict()) - request.session[self.language_session_key] = 'en' + setattr(request, "session", dict()) + request.session[self.language_session_key] = "en" self.assertEqual(user_has_language_set(request), True) def test_user_has_language_set_with_cookie(self): factory = RequestFactory() request = factory.get(self.page_en.get_navigation_url()) - request.COOKIES[django_settings.LANGUAGE_COOKIE_NAME] = 'en' + request.COOKIES[django_settings.LANGUAGE_COOKIE_NAME] = "en" self.assertEqual(user_has_language_set(request), True) def test_translation_set_language_to_session(self): factory = RequestFactory() request = factory.get(self.page_en.get_navigation_url()) - setattr(request, 'session', dict()) - translation_set_language(request, 'en') + setattr(request, "session", dict()) + translation_set_language(request, "en") - self.assertEqual(request.LANGUAGE_CODE, 'en') - self.assertEqual(request.session[self.language_session_key], 'en') + self.assertEqual(request.LANGUAGE_CODE, "en") + self.assertEqual(request.session[self.language_session_key], "en") def test_translation_set_language_to_cookie(self): factory = RequestFactory() request = factory.get(self.page_en.get_navigation_url()) - response = translation_set_language(request, 'en') + response = translation_set_language(request, "en") - self.assertEqual(request.LANGUAGE_CODE, 'en') + self.assertEqual(request.LANGUAGE_CODE, "en") c_key = django_settings.LANGUAGE_COOKIE_NAME - self.assertEqual(response.cookies[c_key].value, 'en') + self.assertEqual(response.cookies[c_key].value, "en") diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index a9c48e0e8..789222679 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -20,6 +20,7 @@ from django.test import TestCase from django.utils import timezone from django.utils.encoding import force_text + try: from django.urls import reverse except ImportError: @@ -45,202 +46,189 @@ # ------------------------------------------------------------------------ class PagesTestCase(TestCase): def setUp(self): - u = User( - username='test', - is_active=True, - is_staff=True, - is_superuser=True) - u.set_password('test') + u = User(username="test", is_active=True, is_staff=True, is_superuser=True) + u.set_password("test") u.save() self.site_1 = Site.objects.all()[0] - Page.register_templates({ - 'key': 'base', - 'title': 'Standard template', - 'path': 'feincms_base.html', - 'regions': ( - ('main', 'Main content area'), - ('sidebar', 'Sidebar', 'inherited'), - ), - }, { - 'key': 'theother', - 'title': 'This actually exists', - 'path': 'base.html', - 'regions': ( - ('main', 'Main content area'), - ('sidebar', 'Sidebar', 'inherited'), - ), - }) + Page.register_templates( + { + "key": "base", + "title": "Standard template", + "path": "feincms_base.html", + "regions": ( + ("main", "Main content area"), + ("sidebar", "Sidebar", "inherited"), + ), + }, + { + "key": "theother", + "title": "This actually exists", + "path": "base.html", + "regions": ( + ("main", "Main content area"), + ("sidebar", "Sidebar", "inherited"), + ), + }, + ) def login(self): - self.assertTrue(self.client.login(username='test', password='test')) + self.assertTrue(self.client.login(username="test", password="test")) - def create_page_through_admin(self, title='Test page', parent='', - **kwargs): + def create_page_through_admin(self, title="Test page", parent="", **kwargs): dic = { - 'title': title, - 'slug': kwargs.get('slug', slugify(title)), - 'parent': parent, - 'template_key': 'base', - 'publication_date_0': '2009-01-01', - 'publication_date_1': '00:00:00', - 'initial-publication_date_0': '2009-01-01', - 'initial-publication_date_1': '00:00:00', - 'language': 'en', - 'navigation_group': 'default', - 'site': self.site_1.id, - - 'rawcontent_set-TOTAL_FORMS': 0, - 'rawcontent_set-INITIAL_FORMS': 0, - 'rawcontent_set-MAX_NUM_FORMS': 10, - - 'mediafilecontent_set-TOTAL_FORMS': 0, - 'mediafilecontent_set-INITIAL_FORMS': 0, - 'mediafilecontent_set-MAX_NUM_FORMS': 10, - - 'imagecontent_set-TOTAL_FORMS': 0, - 'imagecontent_set-INITIAL_FORMS': 0, - 'imagecontent_set-MAX_NUM_FORMS': 10, - - 'contactformcontent_set-TOTAL_FORMS': 0, - 'contactformcontent_set-INITIAL_FORMS': 0, - 'contactformcontent_set-MAX_NUM_FORMS': 10, - - 'filecontent_set-TOTAL_FORMS': 0, - 'filecontent_set-INITIAL_FORMS': 0, - 'filecontent_set-MAX_NUM_FORMS': 10, - - 'templatecontent_set-TOTAL_FORMS': 0, - 'templatecontent_set-INITIAL_FORMS': 0, - 'templatecontent_set-MAX_NUM_FORMS': 10, - - 'applicationcontent_set-TOTAL_FORMS': 0, - 'applicationcontent_set-INITIAL_FORMS': 0, - 'applicationcontent_set-MAX_NUM_FORMS': 10, + "title": title, + "slug": kwargs.get("slug", slugify(title)), + "parent": parent, + "template_key": "base", + "publication_date_0": "2009-01-01", + "publication_date_1": "00:00:00", + "initial-publication_date_0": "2009-01-01", + "initial-publication_date_1": "00:00:00", + "language": "en", + "navigation_group": "default", + "site": self.site_1.id, + "rawcontent_set-TOTAL_FORMS": 0, + "rawcontent_set-INITIAL_FORMS": 0, + "rawcontent_set-MAX_NUM_FORMS": 10, + "mediafilecontent_set-TOTAL_FORMS": 0, + "mediafilecontent_set-INITIAL_FORMS": 0, + "mediafilecontent_set-MAX_NUM_FORMS": 10, + "imagecontent_set-TOTAL_FORMS": 0, + "imagecontent_set-INITIAL_FORMS": 0, + "imagecontent_set-MAX_NUM_FORMS": 10, + "contactformcontent_set-TOTAL_FORMS": 0, + "contactformcontent_set-INITIAL_FORMS": 0, + "contactformcontent_set-MAX_NUM_FORMS": 10, + "filecontent_set-TOTAL_FORMS": 0, + "filecontent_set-INITIAL_FORMS": 0, + "filecontent_set-MAX_NUM_FORMS": 10, + "templatecontent_set-TOTAL_FORMS": 0, + "templatecontent_set-INITIAL_FORMS": 0, + "templatecontent_set-MAX_NUM_FORMS": 10, + "applicationcontent_set-TOTAL_FORMS": 0, + "applicationcontent_set-INITIAL_FORMS": 0, + "applicationcontent_set-MAX_NUM_FORMS": 10, } dic.update(kwargs) - return self.client.post('/admin/page/page/add/', dic) + return self.client.post("/admin/page/page/add/", dic) def create_default_page_set_through_admin(self): self.login() self.create_page_through_admin() - return self.create_page_through_admin('Test child page', 1) + return self.create_page_through_admin("Test child page", 1) - def create_page(self, title='Test page', parent=None, **kwargs): + def create_page(self, title="Test page", parent=None, **kwargs): defaults = { - 'template_key': 'base', - 'site': self.site_1, - 'in_navigation': False, - 'active': False, - 'navigation_group': 'default', + "template_key": "base", + "site": self.site_1, + "in_navigation": False, + "active": False, + "navigation_group": "default", } defaults.update(kwargs) return Page.objects.create( title=title, - slug=kwargs.get('slug', slugify(title)), + slug=kwargs.get("slug", slugify(title)), parent=parent, - **defaults) + **defaults + ) def create_default_page_set(self): - self.create_page( - 'Test child page', - parent=self.create_page(), - ) + self.create_page("Test child page", parent=self.create_page()) def is_published(self, url, should_be=True): try: self.client.get(url) except TemplateDoesNotExist as e: if should_be: - if e.args != ('feincms_base.html',): + if e.args != ("feincms_base.html",): raise else: - if e.args != ('404.html',): + if e.args != ("404.html",): raise def test_01_tree_editor(self): self.login() - self.assertEqual( - self.client.get('/admin/page/page/').status_code, 200) + self.assertEqual(self.client.get("/admin/page/page/").status_code, 200) self.assertRedirects( - self.client.get('/admin/page/page/?anything=anything'), - '/admin/page/page/?e=1') + self.client.get("/admin/page/page/?anything=anything"), + "/admin/page/page/?e=1", + ) def test_02_add_page(self): self.login() self.assertRedirects( - self.create_page_through_admin( - title='Test page ' * 10, - slug='test-page'), - '/admin/page/page/') + self.create_page_through_admin(title="Test page " * 10, slug="test-page"), + "/admin/page/page/", + ) self.assertEqual(Page.objects.count(), 1) - self.assertContains(self.client.get('/admin/page/page/'), '…') + self.assertContains(self.client.get("/admin/page/page/"), "…") def test_03_item_editor(self): self.login() self.assertRedirects( self.create_page_through_admin(_continue=1), - reverse('admin:page_page_change', args=(1,))) + reverse("admin:page_page_change", args=(1,)), + ) self.assertEqual( - self.client.get( - reverse('admin:page_page_change', args=(1,)) - ).status_code, 200) + self.client.get(reverse("admin:page_page_change", args=(1,))).status_code, + 200, + ) self.is_published( - reverse('admin:page_page_change', args=(42,)), - should_be=False) + reverse("admin:page_page_change", args=(42,)), should_be=False + ) def test_03_add_another(self): self.login() self.assertRedirects( - self.create_page_through_admin(_addanother=1), - '/admin/page/page/add/') + self.create_page_through_admin(_addanother=1), "/admin/page/page/add/" + ) def test_04_add_child(self): response = self.create_default_page_set_through_admin() - self.assertRedirects(response, '/admin/page/page/') + self.assertRedirects(response, "/admin/page/page/") self.assertEqual(Page.objects.count(), 2) page = Page.objects.get(pk=2) - self.assertEqual( - page.get_absolute_url(), '/test-page/test-child-page/') + self.assertEqual(page.get_absolute_url(), "/test-page/test-child-page/") page.active = True page.in_navigation = True page.save() # page2 inherited the inactive flag from the toplevel page - self.assertContains(self.client.get('/admin/page/page/'), 'inherited') + self.assertContains(self.client.get("/admin/page/page/"), "inherited") page1 = Page.objects.get(pk=1) page1.active = True page1.save() - content = self.client.get('/admin/page/page/').content.decode('utf-8') + content = self.client.get("/admin/page/page/").content.decode("utf-8") self.assertEqual(len(content.split('checked="checked"')), 4) def test_05_override_url(self): self.create_default_page_set() page = Page.objects.get(pk=1) - page.override_url = '/something/' + page.override_url = "/something/" page.save() page2 = Page.objects.get(pk=2) - self.assertEqual( - page2.get_absolute_url(), '/something/test-child-page/') + self.assertEqual(page2.get_absolute_url(), "/something/test-child-page/") - page.override_url = '/' + page.override_url = "/" page.save() page2 = Page.objects.get(pk=2) - self.assertEqual(page2.get_absolute_url(), '/test-child-page/') + self.assertEqual(page2.get_absolute_url(), "/test-child-page/") - self.is_published('/', False) + self.is_published("/", False) page.active = True - page.template_key = 'theother' + page.template_key = "theother" page.save() - self.is_published('/', True) + self.is_published("/", True) def test_06_tree_editor_save(self): self.create_default_page_set() @@ -248,29 +236,32 @@ def test_06_tree_editor_save(self): page1 = Page.objects.get(pk=1) page2 = Page.objects.get(pk=2) - page3 = Page.objects.create(title='page3', slug='page3', parent=page2) - page4 = Page.objects.create(title='page4', slug='page4', parent=page1) - page5 = Page.objects.create(title='page5', slug='page5', parent=None) + page3 = Page.objects.create(title="page3", slug="page3", parent=page2) + page4 = Page.objects.create(title="page4", slug="page4", parent=page1) + page5 = Page.objects.create(title="page5", slug="page5", parent=None) - self.assertEqual( - page3.get_absolute_url(), '/test-page/test-child-page/page3/') - self.assertEqual(page4.get_absolute_url(), '/test-page/page4/') - self.assertEqual(page5.get_absolute_url(), '/page5/') + self.assertEqual(page3.get_absolute_url(), "/test-page/test-child-page/page3/") + self.assertEqual(page4.get_absolute_url(), "/test-page/page4/") + self.assertEqual(page5.get_absolute_url(), "/page5/") self.login() - self.client.post('/admin/page/page/', { - '__cmd': 'move_node', - 'position': 'last-child', - 'cut_item': '1', - 'pasted_on': '5', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - self.assertEqual(Page.objects.get(pk=1).get_absolute_url(), - '/page5/test-page/') - self.assertEqual(Page.objects.get(pk=5).get_absolute_url(), - '/page5/') - self.assertEqual(Page.objects.get(pk=3).get_absolute_url(), - '/page5/test-page/test-child-page/page3/') + self.client.post( + "/admin/page/page/", + { + "__cmd": "move_node", + "position": "last-child", + "cut_item": "1", + "pasted_on": "5", + }, + HTTP_X_REQUESTED_WITH="XMLHttpRequest", + ) + + self.assertEqual(Page.objects.get(pk=1).get_absolute_url(), "/page5/test-page/") + self.assertEqual(Page.objects.get(pk=5).get_absolute_url(), "/page5/") + self.assertEqual( + Page.objects.get(pk=3).get_absolute_url(), + "/page5/test-page/test-child-page/page3/", + ) def test_07_tree_editor_toggle_boolean(self): self.create_default_page_set() @@ -279,38 +270,46 @@ def test_07_tree_editor_toggle_boolean(self): self.login() self.assertContains( - self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'in_navigation', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), - r'checked=\"checked\"') + self.client.post( + "/admin/page/page/", + {"__cmd": "toggle_boolean", "item_id": 1, "attr": "in_navigation"}, + HTTP_X_REQUESTED_WITH="XMLHttpRequest", + ), + r"checked=\"checked\"", + ) self.assertEqual(Page.objects.get(pk=1).in_navigation, True) self.assertNotContains( - self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'in_navigation', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), - 'checked="checked"') + self.client.post( + "/admin/page/page/", + {"__cmd": "toggle_boolean", "item_id": 1, "attr": "in_navigation"}, + HTTP_X_REQUESTED_WITH="XMLHttpRequest", + ), + 'checked="checked"', + ) self.assertEqual(Page.objects.get(pk=1).in_navigation, False) - self.assertTrue(isinstance( - self.client.post('/admin/page/page/', { - '__cmd': 'toggle_boolean', - 'item_id': 1, - 'attr': 'notexists', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), - HttpResponseBadRequest)) + self.assertTrue( + isinstance( + self.client.post( + "/admin/page/page/", + {"__cmd": "toggle_boolean", "item_id": 1, "attr": "notexists"}, + HTTP_X_REQUESTED_WITH="XMLHttpRequest", + ), + HttpResponseBadRequest, + ) + ) def test_07_tree_editor_invalid_ajax(self): self.login() self.assertContains( - self.client.post('/admin/page/page/', { - '__cmd': 'notexists', - }, HTTP_X_REQUESTED_WITH='XMLHttpRequest'), - 'Oops. AJAX request not understood.', - status_code=400) + self.client.post( + "/admin/page/page/", + {"__cmd": "notexists"}, + HTTP_X_REQUESTED_WITH="XMLHttpRequest", + ), + "Oops. AJAX request not understood.", + status_code=400, + ) def test_08_publishing(self): self.create_default_page_set() @@ -350,47 +349,41 @@ def test_08_publishing(self): def create_page_through_admincontent(self, page, **kwargs): data = { - 'title': page.title, - 'slug': page.slug, + "title": page.title, + "slug": page.slug, # 'parent': page.parent_id, # this field is excluded from the form - 'template_key': page.template_key, - 'publication_date_0': '2009-01-01', - 'publication_date_1': '00:00:00', - 'initial-publication_date_0': '2009-01-01', - 'initial-publication_date_1': '00:00:00', - 'language': 'en', - 'navigation_group': 'default', - 'site': self.site_1.id, - - 'rawcontent_set-TOTAL_FORMS': 1, - 'rawcontent_set-INITIAL_FORMS': 0, - 'rawcontent_set-MAX_NUM_FORMS': 10, - - 'rawcontent_set-0-parent': 1, - 'rawcontent_set-0-region': 'main', - 'rawcontent_set-0-ordering': 0, - 'rawcontent_set-0-text': 'This is some example content', - - 'mediafilecontent_set-TOTAL_FORMS': 1, - 'mediafilecontent_set-INITIAL_FORMS': 0, - 'mediafilecontent_set-MAX_NUM_FORMS': 10, - - 'mediafilecontent_set-0-parent': 1, - 'mediafilecontent_set-0-type': 'default', - - 'templatecontent_set-TOTAL_FORMS': 1, - 'templatecontent_set-INITIAL_FORMS': 0, - 'templatecontent_set-MAX_NUM_FORMS': 10, - - 'applicationcontent_set-TOTAL_FORMS': 1, - 'applicationcontent_set-INITIAL_FORMS': 0, - 'applicationcontent_set-MAX_NUM_FORMS': 10, + "template_key": page.template_key, + "publication_date_0": "2009-01-01", + "publication_date_1": "00:00:00", + "initial-publication_date_0": "2009-01-01", + "initial-publication_date_1": "00:00:00", + "language": "en", + "navigation_group": "default", + "site": self.site_1.id, + "rawcontent_set-TOTAL_FORMS": 1, + "rawcontent_set-INITIAL_FORMS": 0, + "rawcontent_set-MAX_NUM_FORMS": 10, + "rawcontent_set-0-parent": 1, + "rawcontent_set-0-region": "main", + "rawcontent_set-0-ordering": 0, + "rawcontent_set-0-text": "This is some example content", + "mediafilecontent_set-TOTAL_FORMS": 1, + "mediafilecontent_set-INITIAL_FORMS": 0, + "mediafilecontent_set-MAX_NUM_FORMS": 10, + "mediafilecontent_set-0-parent": 1, + "mediafilecontent_set-0-type": "default", + "templatecontent_set-TOTAL_FORMS": 1, + "templatecontent_set-INITIAL_FORMS": 0, + "templatecontent_set-MAX_NUM_FORMS": 10, + "applicationcontent_set-TOTAL_FORMS": 1, + "applicationcontent_set-INITIAL_FORMS": 0, + "applicationcontent_set-MAX_NUM_FORMS": 10, } data.update(kwargs) return self.client.post( - reverse('admin:page_page_change', args=(page.pk,)), - data) + reverse("admin:page_page_change", args=(page.pk,)), data + ) def test_09_pagecontent(self): self.create_default_page_set() @@ -398,8 +391,8 @@ def test_09_pagecontent(self): page = Page.objects.get(pk=1) self.login() response = self.create_page_through_admincontent(page) - self.assertRedirects(response, '/admin/page/page/') - self.assertEqual(page.content.main[0].__class__.__name__, 'RawContent') + self.assertRedirects(response, "/admin/page/page/") + self.assertEqual(page.content.main[0].__class__.__name__, "RawContent") page2 = Page.objects.get(pk=2) page2.symlinked_page = page @@ -408,12 +401,12 @@ def test_09_pagecontent(self): # other content methods self.assertEqual(len(page2.content.all_of_type(RawContent)), 1) - self.assertEqual( - page2.content.main[0].__class__.__name__, 'RawContent') + self.assertEqual(page2.content.main[0].__class__.__name__, "RawContent") self.assertEqual( force_text(page2.content.main[0]), - 'RawContent, region=main,' - ' ordering=0>') + "RawContent, region=main," + " ordering=0>", + ) self.assertEqual(len(page2.content.main), 1) self.assertEqual(len(page2.content.sidebar), 0) @@ -430,73 +423,72 @@ def test_10_mediafile_and_imagecontent(self): page = Page.objects.get(pk=1) self.create_page_through_admincontent(page) - category = Category.objects.create(title='Category', parent=None) - category2 = Category.objects.create(title='Something', parent=category) + category = Category.objects.create(title="Category", parent=None) + category2 = Category.objects.create(title="Something", parent=category) - self.assertEqual(force_text(category2), 'Category - Something') - self.assertEqual(force_text(category), 'Category') + self.assertEqual(force_text(category2), "Category - Something") + self.assertEqual(force_text(category), "Category") - mediafile = MediaFile.objects.create(file='somefile.jpg') + mediafile = MediaFile.objects.create(file="somefile.jpg") if django.VERSION < (2, 0): mediafile.categories = [category] else: mediafile.categories.set([category]) page.mediafilecontent_set.create( - mediafile=mediafile, - region='main', - type='default', - ordering=1) + mediafile=mediafile, region="main", type="default", ordering=1 + ) - self.assertEqual(force_text(mediafile), 'somefile.jpg') + self.assertEqual(force_text(mediafile), "somefile.jpg") mediafile.translations.create( - caption='something', language_code='%s-ha' % short_language_code()) + caption="something", language_code="%s-ha" % short_language_code() + ) mediafile.purge_translation_cache() - self.assertTrue('something' in force_text(mediafile)) + self.assertTrue("something" in force_text(mediafile)) mf = page.content.main[1].mediafile - self.assertEqual(mf.translation.caption, 'something') - self.assertEqual( - mf.translation.short_language_code(), short_language_code()) - self.assertNotEqual(mf.get_absolute_url(), '') - self.assertEqual(force_text(mf), 'something') - self.assertTrue(mf.type == 'image') + self.assertEqual(mf.translation.caption, "something") + self.assertEqual(mf.translation.short_language_code(), short_language_code()) + self.assertNotEqual(mf.get_absolute_url(), "") + self.assertEqual(force_text(mf), "something") + self.assertTrue(mf.type == "image") - self.assertEqual(MediaFile.objects.only_language('de').count(), 0) - self.assertEqual(MediaFile.objects.only_language('en').count(), 0) + self.assertEqual(MediaFile.objects.only_language("de").count(), 0) + self.assertEqual(MediaFile.objects.only_language("en").count(), 0) self.assertEqual( MediaFile.objects.only_language( - lambda: '%s-ha' % short_language_code() + lambda: "%s-ha" % short_language_code() ).count(), 1, ) - self.assertTrue( - '%s-ha' % short_language_code() in mf.available_translations) + self.assertTrue("%s-ha" % short_language_code() in mf.available_translations) # this should not raise - self.client.get(reverse('admin:page_page_change', args=(1,))) + self.client.get(reverse("admin:page_page_change", args=(1,))) page.mediafilecontent_set.update(mediafile=3) # this should not raise - self.client.get('/admin/page/page/1/') + self.client.get("/admin/page/page/1/") - field = MediaFile._meta.get_field('file') + field = MediaFile._meta.get_field("file") old = (field.upload_to, field.storage, field.generate_filename) from django.core.files.storage import FileSystemStorage + MediaFile.reconfigure( - upload_to=lambda: 'anywhere', - storage=FileSystemStorage(location='/wha/', base_url='/whe/')) + upload_to=lambda: "anywhere", + storage=FileSystemStorage(location="/wha/", base_url="/whe/"), + ) mediafile = MediaFile.objects.get(pk=1) - self.assertEqual(mediafile.file.url, '/whe/somefile.jpg') + self.assertEqual(mediafile.file.url, "/whe/somefile.jpg") # restore settings (field.upload_to, field.storage, field.generate_filename) = old mediafile = MediaFile.objects.get(pk=1) - self.assertEqual(mediafile.file.url, '/media/somefile.jpg') + self.assertEqual(mediafile.file.url, "/media/somefile.jpg") def test_11_translations(self): self.create_default_page_set() @@ -511,7 +503,7 @@ def test_11_translations(self): page1.save() page2.active = True - page2.language = 'de' + page2.language = "de" page2.save() self.assertEqual(len(page2.available_translations()), 0) @@ -533,62 +525,50 @@ def test_12_titles(self): self.assertEqual(page.page_title, page.title) self.assertEqual(page.content_title, page.title) - page._content_title = 'Something\nawful' - page._page_title = 'Hello world' + page._content_title = "Something\nawful" + page._page_title = "Hello world" page.save() - self.assertEqual(page.page_title, 'Hello world') - self.assertEqual(page.content_title, 'Something') - self.assertEqual(page.content_subtitle, 'awful') + self.assertEqual(page.page_title, "Hello world") + self.assertEqual(page.content_title, "Something") + self.assertEqual(page.content_subtitle, "awful") - page._content_title = 'Only one line' - self.assertEqual(page.content_title, 'Only one line') - self.assertEqual(page.content_subtitle, '') + page._content_title = "Only one line" + self.assertEqual(page.content_title, "Only one line") + self.assertEqual(page.content_subtitle, "") - page._content_title = '' + page._content_title = "" self.assertEqual(page.content_title, page.title) - self.assertEqual(page.content_subtitle, '') + self.assertEqual(page.content_subtitle, "") def test_13_inheritance_and_ct_tracker(self): self.create_default_page_set() page = Page.objects.get(pk=1) - page.rawcontent_set.create( - region='sidebar', - ordering=0, - text='Something') - page.rawcontent_set.create( - region='main', - ordering=0, - text='Anything') + page.rawcontent_set.create(region="sidebar", ordering=0, text="Something") + page.rawcontent_set.create(region="main", ordering=0, text="Anything") page2 = Page.objects.get(pk=2) - page2.rawcontent_set.create( - region='main', - ordering=0, - text='Something else') - page2.rawcontent_set.create( - region='main', - ordering=1, - text='Whatever') + page2.rawcontent_set.create(region="main", ordering=0, text="Something else") + page2.rawcontent_set.create(region="main", ordering=1, text="Whatever") # Set default, non-caching content proxy page2.content_proxy_class = ContentProxy - if hasattr(self, 'assertNumQueries'): + if hasattr(self, "assertNumQueries"): # 4 queries: Two to get the content types of page and page2, one to # fetch all ancestor PKs of page2 and one to materialize the # RawContent instances belonging to page's sidebar and page2's # main. self.assertNumQueries( - 4, lambda: [page2.content.main, page2.content.sidebar]) - self.assertNumQueries( - 0, lambda: page2.content.sidebar[0].render()) + 4, lambda: [page2.content.main, page2.content.sidebar] + ) + self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) self.assertEqual( - ''.join(c.render() for c in page2.content.main), - 'Something elseWhatever') - self.assertEqual(page2.content.sidebar[0].render(), 'Something') + "".join(c.render() for c in page2.content.main), "Something elseWhatever" + ) + self.assertEqual(page2.content.sidebar[0].render(), "Something") page2 = Page.objects.get(pk=2) self.assertEqual(page2._ct_inventory, {}) @@ -597,7 +577,7 @@ def test_13_inheritance_and_ct_tracker(self): for ct in Page._feincms_content_types: ContentType.objects.get_for_model(ct) - if hasattr(self, 'assertNumQueries'): + if hasattr(self, "assertNumQueries"): # 5 queries: Two to get the content types of page and page2, one to # fetch all ancestor PKs of page2 and one to materialize the # RawContent instances belonging to page's sidebar and page2's main @@ -606,18 +586,19 @@ def test_13_inheritance_and_ct_tracker(self): # - one update to clobber the _ct_inventory attribute of all # descendants of page2 self.assertNumQueries( - 5, lambda: [page2.content.main, page2.content.sidebar]) - self.assertNumQueries( - 0, lambda: page2.content.sidebar[0].render()) + 5, lambda: [page2.content.main, page2.content.sidebar] + ) + self.assertNumQueries(0, lambda: page2.content.sidebar[0].render()) - self.assertEqual(page2.content.sidebar[0].render(), 'Something') + self.assertEqual(page2.content.sidebar[0].render(), "Something") # Reload, again, to test ct_tracker extension page2 = Page.objects.get(pk=2) - if hasattr(self, 'assertNumQueries'): + if hasattr(self, "assertNumQueries"): self.assertNumQueries( - 1, lambda: [page2.content.main, page2.content.sidebar]) + 1, lambda: [page2.content.main, page2.content.sidebar] + ) self.assertNotEqual(page2._ct_inventory, {}) @@ -625,13 +606,13 @@ def test_14_richtext(self): # only create the content type to test the item editor # customization hooks tmp = Page._feincms_content_types[:] - type = Page.create_content_type( - RichTextContent, regions=('notexists',)) + type = Page.create_content_type(RichTextContent, regions=("notexists",)) Page._feincms_content_types = tmp from django.utils.safestring import SafeData + obj = type() - obj.text = 'Something' + obj.text = "Something" self.assertTrue(isinstance(obj.render(), SafeData)) def test_17_page_template_tags(self): @@ -640,7 +621,7 @@ def test_17_page_template_tags(self): page1 = Page.objects.get(pk=1) page2 = Page.objects.get(pk=2) - page2.language = 'de' + page2.language = "de" page2.translation_of = page1 page2.active = True page2.in_navigation = True @@ -648,9 +629,9 @@ def test_17_page_template_tags(self): page3 = Page.objects.create( parent=page2, - title='page3', - slug='page3', - language='en', + title="page3", + slug="page3", + language="en", active=True, in_navigation=True, publication_date=datetime(2001, 1, 1), @@ -660,51 +641,55 @@ def test_17_page_template_tags(self): page1 = Page.objects.get(pk=1) page2 = Page.objects.get(pk=2) - context = template.Context({'feincms_page': page2, 'page3': page3}) + context = template.Context({"feincms_page": page2, "page3": page3}) t = template.Template( - '{% load feincms_page_tags %}{% feincms_parentlink of feincms_page' - ' level=1 %}') - self.assertEqual(t.render(context), '/test-page/') + "{% load feincms_page_tags %}{% feincms_parentlink of feincms_page" + " level=1 %}" + ) + self.assertEqual(t.render(context), "/test-page/") t = template.Template( - '{% load feincms_page_tags %}{% feincms_languagelinks for' - ' feincms_page as links %}{% for key, name, link in links %}' - '{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}' - '{% endfor %}') + "{% load feincms_page_tags %}{% feincms_languagelinks for" + " feincms_page as links %}{% for key, name, link in links %}" + "{{ key }}:{{ link }}{% if not forloop.last %},{% endif %}" + "{% endfor %}" + ) self.assertEqual( - t.render(context), - 'en:/test-page/,de:/test-page/test-child-page/') + t.render(context), "en:/test-page/,de:/test-page/test-child-page/" + ) t = template.Template( - '{% load feincms_page_tags %}{% feincms_languagelinks for page3' - ' as links %}{% for key, name, link in links %}{{ key }}:' - '{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') + "{% load feincms_page_tags %}{% feincms_languagelinks for page3" + " as links %}{% for key, name, link in links %}{{ key }}:" + "{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}" + ) self.assertEqual( - t.render(context), - 'en:/test-page/test-child-page/page3/,de:None') + t.render(context), "en:/test-page/test-child-page/page3/,de:None" + ) t = template.Template( - '{% load feincms_page_tags %}{% feincms_languagelinks for page3' - ' as links existing %}{% for key, name, link in links %}{{ key }}:' - '{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual( - t.render(context), - 'en:/test-page/test-child-page/page3/') + "{% load feincms_page_tags %}{% feincms_languagelinks for page3" + " as links existing %}{% for key, name, link in links %}{{ key }}:" + "{{ link }}{% if not forloop.last %},{% endif %}{% endfor %}" + ) + self.assertEqual(t.render(context), "en:/test-page/test-child-page/page3/") t = template.Template( - '{% load feincms_page_tags %}{% feincms_languagelinks for' - ' feincms_page as links excludecurrent=1 %}' - '{% for key, name, link in links %}{{ key }}:{{ link }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), 'en:/test-page/') + "{% load feincms_page_tags %}{% feincms_languagelinks for" + " feincms_page as links excludecurrent=1 %}" + "{% for key, name, link in links %}{{ key }}:{{ link }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) + self.assertEqual(t.render(context), "en:/test-page/") t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=1 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '') + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=1 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) + self.assertEqual(t.render(context), "") # XXX should the other template tags not respect the in_navigation # setting too? @@ -712,101 +697,114 @@ def test_17_page_template_tags(self): page1.in_navigation = True page1.save() - self.assertEqual(t.render(context), '/test-page/') + self.assertEqual(t.render(context), "/test-page/") t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '/test-page/test-child-page/') + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) + self.assertEqual(t.render(context), "/test-page/test-child-page/") t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav request level=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') + "{% load feincms_page_tags %}" + "{% feincms_nav request level=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) from django.http import HttpRequest + request = HttpRequest() - request.path = '/test-page/' + request.path = "/test-page/" self.assertEqual( - t.render(template.Context({'request': request})), - '/test-page/test-child-page/') + t.render(template.Context({"request": request})), + "/test-page/test-child-page/", + ) t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=99 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual(t.render(context), '') + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=99 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) + self.assertEqual(t.render(context), "") t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_breadcrumbs feincms_page %}') + "{% load feincms_page_tags %}" "{% feincms_breadcrumbs feincms_page %}" + ) rendered = t.render(context) self.assertTrue("Test child page" in rendered) self.assertTrue( 'href="/test-page/">Test page' in rendered, - msg="The parent page should be a breadcrumb link") + msg="The parent page should be a breadcrumb link", + ) self.assertTrue( 'href="/test-page/test-child-page/"' not in rendered, - msg="The current page should not be a link in the breadcrumbs") + msg="The current page should not be a link in the breadcrumbs", + ) t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=2 depth=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=2 depth=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) self.assertEqual( t.render(context), - '/test-page/test-child-page/,/test-page/test-child-page/page3/') + "/test-page/test-child-page/,/test-page/test-child-page/page3/", + ) t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=1 depth=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual( - t.render(context), - '/test-page/,/test-page/test-child-page/') + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=1 depth=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) + self.assertEqual(t.render(context), "/test-page/,/test-page/test-child-page/") t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=1 depth=3 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=1 depth=3 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) self.assertEqual( t.render(context), - '/test-page/,/test-page/test-child-page/,/test-page/test-child' - '-page/page3/') + "/test-page/,/test-page/test-child-page/,/test-page/test-child" + "-page/page3/", + ) t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=3 depth=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}') - self.assertEqual( - t.render(context), '/test-page/test-child-page/page3/') + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=3 depth=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}" + ) + self.assertEqual(t.render(context), "/test-page/test-child-page/page3/") t = template.Template( - '{% load feincms_page_tags %}' - '{% if feincms_page|is_parent_of:page3 %}yes{% endif %}|' - '{% if page3|is_parent_of:feincms_page %}yes{% endif %}') - self.assertEqual(t.render(context), 'yes|') + "{% load feincms_page_tags %}" + "{% if feincms_page|is_parent_of:page3 %}yes{% endif %}|" + "{% if page3|is_parent_of:feincms_page %}yes{% endif %}" + ) + self.assertEqual(t.render(context), "yes|") t = template.Template( - '{% load feincms_page_tags %}' - '{% if feincms_page|is_equal_or_parent_of:page3 %}yes{% endif %}|' - '{% if page3|is_equal_or_parent_of:feincms_page %}yes{% endif %}') - self.assertEqual(t.render(context), 'yes|') + "{% load feincms_page_tags %}" + "{% if feincms_page|is_equal_or_parent_of:page3 %}yes{% endif %}|" + "{% if page3|is_equal_or_parent_of:feincms_page %}yes{% endif %}" + ) + self.assertEqual(t.render(context), "yes|") t = template.Template( - '{% load feincms_page_tags %}' - '{% feincms_translatedpage for feincms_page as t1 language=de %}' - '{% feincms_translatedpage for feincms_page as t2 %}' - '{{ t1.id }}|{{ t2.id }}') - self.assertEqual(t.render(context), '2|1') + "{% load feincms_page_tags %}" + "{% feincms_translatedpage for feincms_page as t1 language=de %}" + "{% feincms_translatedpage for feincms_page as t2 %}" + "{{ t1.id }}|{{ t2.id }}" + ) + self.assertEqual(t.render(context), "2|1") def test_17_feincms_nav(self): """ @@ -815,30 +813,30 @@ def test_17_feincms_nav(self): self.login() - self.create_page_through_admin('Page 1') # 1 - self.create_page_through_admin('Page 1.1', 1) - self.create_page_through_admin('Page 1.2', 1) # 3 - self.create_page_through_admin('Page 1.2.1', 3) - self.create_page_through_admin('Page 1.2.2', 3) - self.create_page_through_admin('Page 1.2.3', 3) - self.create_page_through_admin('Page 1.3', 1) - - self.create_page_through_admin('Page 2') # 8 - self.create_page_through_admin('Page 2.1', 8) - self.create_page_through_admin('Page 2.2', 8) - self.create_page_through_admin('Page 2.3', 8) - - self.create_page_through_admin('Page 3') # 12 - self.create_page_through_admin('Page 3.1', 12) - self.create_page_through_admin('Page 3.2', 12) - self.create_page_through_admin('Page 3.3', 12) # 15 - self.create_page_through_admin('Page 3.3.1', 15) # 16 - self.create_page_through_admin('Page 3.3.1.1', 16) - self.create_page_through_admin('Page 3.3.2', 15) - - self.create_page_through_admin('Page 4') # 19 - self.create_page_through_admin('Page 4.1', 19) - self.create_page_through_admin('Page 4.2', 19) + self.create_page_through_admin("Page 1") # 1 + self.create_page_through_admin("Page 1.1", 1) + self.create_page_through_admin("Page 1.2", 1) # 3 + self.create_page_through_admin("Page 1.2.1", 3) + self.create_page_through_admin("Page 1.2.2", 3) + self.create_page_through_admin("Page 1.2.3", 3) + self.create_page_through_admin("Page 1.3", 1) + + self.create_page_through_admin("Page 2") # 8 + self.create_page_through_admin("Page 2.1", 8) + self.create_page_through_admin("Page 2.2", 8) + self.create_page_through_admin("Page 2.3", 8) + + self.create_page_through_admin("Page 3") # 12 + self.create_page_through_admin("Page 3.1", 12) + self.create_page_through_admin("Page 3.2", 12) + self.create_page_through_admin("Page 3.3", 12) # 15 + self.create_page_through_admin("Page 3.3.1", 15) # 16 + self.create_page_through_admin("Page 3.3.1.1", 16) + self.create_page_through_admin("Page 3.3.2", 15) + + self.create_page_through_admin("Page 4") # 19 + self.create_page_through_admin("Page 4.1", 19) + self.create_page_through_admin("Page 4.2", 19) """ Creates the following structure: @@ -866,122 +864,125 @@ def test_17_feincms_nav(self): tests = [ ( - {'feincms_page': Page.objects.get(pk=1)}, - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=1 depth=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/' - ',/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-' - '3/page-31/,/page-3/page-32/,/page-3/page-33/', + {"feincms_page": Page.objects.get(pk=1)}, + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=1 depth=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}", + "/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13/" + ",/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/page-" + "3/page-31/,/page-3/page-32/,/page-3/page-33/", ), ( - {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=2 depth=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/' - 'page-33/page-331/,/page-3/page-33/page-332/', + {"feincms_page": Page.objects.get(pk=14)}, + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=2 depth=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}", + "/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/" + "page-33/page-331/,/page-3/page-33/page-332/", ), ( - {'feincms_page': Page.objects.get(pk=14)}, - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=2 depth=3 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/' - 'page-33/page-331/,/page-3/page-33/page-331/page-3311/,/page' - '-3/page-33/page-332/', + {"feincms_page": Page.objects.get(pk=14)}, + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=2 depth=3 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}", + "/page-3/page-31/,/page-3/page-32/,/page-3/page-33/,/page-3/" + "page-33/page-331/,/page-3/page-33/page-331/page-3311/,/page" + "-3/page-33/page-332/", ), ( - {'feincms_page': Page.objects.get(pk=19)}, - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=1 depth=2 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}', - '/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13' - '/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/pag' - 'e-3/page-31/,/page-3/page-32/,/page-3/page-33/', + {"feincms_page": Page.objects.get(pk=19)}, + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=1 depth=2 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}", + "/page-1/,/page-1/page-11/,/page-1/page-12/,/page-1/page-13" + "/,/page-2/,/page-2/page-22/,/page-2/page-23/,/page-3/,/pag" + "e-3/page-31/,/page-3/page-32/,/page-3/page-33/", ), ( - {'feincms_page': Page.objects.get(pk=1)}, - '{% load feincms_page_tags %}' - '{% feincms_nav feincms_page level=3 depth=1 as nav %}' - '{% for p in nav %}{{ p.get_absolute_url }}' - '{% if not forloop.last %},{% endif %}{% endfor %}', - '', + {"feincms_page": Page.objects.get(pk=1)}, + "{% load feincms_page_tags %}" + "{% feincms_nav feincms_page level=3 depth=1 as nav %}" + "{% for p in nav %}{{ p.get_absolute_url }}" + "{% if not forloop.last %},{% endif %}{% endfor %}", + "", ), ] for c, t, r in tests: - self.assertEqual( - template.Template(t).render(template.Context(c)), - r) + self.assertEqual(template.Template(t).render(template.Context(c)), r) # Test that navigation entries do not exist several times, even with # navigation extensions. Apply the PassthroughExtension to a page # which does only have direct children, because it does not collect # pages further down the tree. page = Page.objects.get(pk=8) - page.navigation_extension =\ - 'testapp.navigation_extensions.PassthroughExtension' + page.navigation_extension = "testapp.navigation_extensions.PassthroughExtension" page.save() for c, t, r in tests: - self.assertEqual( - template.Template(t).render(template.Context(c)), - r) + self.assertEqual(template.Template(t).render(template.Context(c)), r) # Now check that disabling a page also disables it in Navigation: p = Page.objects.get(pk=15) - tmpl = '''{% load feincms_page_tags %} + tmpl = """{% load feincms_page_tags %} {% feincms_nav feincms_page level=1 depth=3 as nav %} {% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %} -''' +""" - data = template.Template(tmpl).render( - template.Context({'feincms_page': p}) - ).strip(), + data = ( + template.Template(tmpl) + .render(template.Context({"feincms_page": p})) + .strip(), + ) self.assertEqual( - data, - ('1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), - "Original navigation") + data, ("1,2,3,4,6,7,8,10,11,12,13,14,15,16,18",), "Original navigation" + ) p.active = False p.save() - data = template.Template(tmpl).render( - template.Context({'feincms_page': p}) - ).strip(), + data = ( + template.Template(tmpl) + .render(template.Context({"feincms_page": p})) + .strip(), + ) self.assertEqual( data, - ('1,2,3,4,6,7,8,10,11,12,13,14',), - "Navigation after disabling intermediate page") + ("1,2,3,4,6,7,8,10,11,12,13,14",), + "Navigation after disabling intermediate page", + ) # Same test with feincms_nav - tmpl = '''{% load feincms_page_tags %} + tmpl = """{% load feincms_page_tags %} {% feincms_nav feincms_page level=1 depth=3 as nav %} {% for p in nav %}{{ p.pk }}{% if not forloop.last %},{% endif %}{% endfor %} -''' +""" - data = template.Template(tmpl).render( - template.Context({'feincms_page': p}) - ).strip(), + data = ( + template.Template(tmpl) + .render(template.Context({"feincms_page": p})) + .strip(), + ) self.assertEqual( data, - ('1,2,3,4,6,7,8,10,11,12,13,14',), - "Navigation after disabling intermediate page") + ("1,2,3,4,6,7,8,10,11,12,13,14",), + "Navigation after disabling intermediate page", + ) p.active = True p.save() - data = template.Template(tmpl).render( - template.Context({'feincms_page': p}) - ).strip(), + data = ( + template.Template(tmpl) + .render(template.Context({"feincms_page": p})) + .strip(), + ) self.assertEqual( - data, - ('1,2,3,4,6,7,8,10,11,12,13,14,15,16,18',), - "Original navigation") + data, ("1,2,3,4,6,7,8,10,11,12,13,14,15,16,18",), "Original navigation" + ) def test_18_default_render_method(self): """ @@ -994,17 +995,17 @@ class Meta: abstract = True def render_main(self): - return 'Hello' + return "Hello" # do not register this model in the internal FeinCMS bookkeeping # structures tmp = Page._feincms_content_types[:] - type = Page.create_content_type(Something, regions=('notexists',)) + type = Page.create_content_type(Something, regions=("notexists",)) Page._feincms_content_types = tmp - s = type(region='main', ordering='1') + s = type(region="main", ordering="1") - self.assertEqual(s.render(), 'Hello') + self.assertEqual(s.render(), "Hello") def test_19_page_manager(self): self.create_default_page_set() @@ -1015,73 +1016,78 @@ def test_19_page_manager(self): self.assertRaises( Page.DoesNotExist, - lambda: Page.objects.page_for_path(page.get_absolute_url())) + lambda: Page.objects.page_for_path(page.get_absolute_url()), + ) self.assertRaises( Page.DoesNotExist, lambda: Page.objects.best_match_for_path( - page.get_absolute_url() + 'something/hello/')) + page.get_absolute_url() + "something/hello/" + ), + ) self.assertRaises( Http404, - lambda: Page.objects.best_match_for_path( - '/blabla/blabla/', raise404=True)) + lambda: Page.objects.best_match_for_path("/blabla/blabla/", raise404=True), + ) self.assertRaises( - Http404, - lambda: Page.objects.page_for_path('/asdf/', raise404=True)) + Http404, lambda: Page.objects.page_for_path("/asdf/", raise404=True) + ) self.assertRaises( Page.DoesNotExist, - lambda: Page.objects.best_match_for_path('/blabla/blabla/')) + lambda: Page.objects.best_match_for_path("/blabla/blabla/"), + ) self.assertRaises( - Page.DoesNotExist, - lambda: Page.objects.page_for_path('/asdf/')) + Page.DoesNotExist, lambda: Page.objects.page_for_path("/asdf/") + ) request = Empty() request.path = request.path_info = page.get_absolute_url() - request.method = 'GET' - request.get_full_path = lambda: '/xyz/' + request.method = "GET" + request.get_full_path = lambda: "/xyz/" request.GET = {} request.META = {} request.user = AnonymousUser() # tadaa from django.utils import translation + translation.activate(page.language) page.active = False page.save() self.assertRaises( - Http404, - lambda: Page.objects.for_request(request, raise404=True)) + Http404, lambda: Page.objects.for_request(request, raise404=True) + ) page.active = True page.save() self.assertRaises( - Http404, - lambda: Page.objects.for_request(request, raise404=True)) + Http404, lambda: Page.objects.for_request(request, raise404=True) + ) page.parent.active = True page.parent.save() self.assertEqual(page, Page.objects.for_request(request)) - self.assertEqual( - page, Page.objects.page_for_path(page.get_absolute_url())) + self.assertEqual(page, Page.objects.page_for_path(page.get_absolute_url())) self.assertEqual( page, Page.objects.best_match_for_path( - page.get_absolute_url() + 'something/hello/')) + page.get_absolute_url() + "something/hello/" + ), + ) old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH - request.path += 'hello/' + request.path += "hello/" feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = False self.assertEqual(self.client.get(request.path).status_code, 404) feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True self.assertEqual(self.client.get(request.path).status_code, 200) - self.assertEqual( - page, Page.objects.for_request(request, best_match=True)) + self.assertEqual(page, Page.objects.for_request(request, best_match=True)) feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old @@ -1096,7 +1102,7 @@ def test_20_redirects(self): page2.active = True page2.publication_date = timezone.now() - timedelta(days=1) - page2.override_url = '/blablabla/' + page2.override_url = "/blablabla/" page2.redirect_to = page1.get_absolute_url() page2.save() @@ -1109,11 +1115,11 @@ def test_20_redirects(self): # page2 has been modified too, but its URL should not have changed try: self.assertRedirects( - self.client.get('/blablabla/'), - page1.get_absolute_url()) + self.client.get("/blablabla/"), page1.get_absolute_url() + ) except TemplateDoesNotExist as e: # catch the error from rendering page1 - if e.args != ('feincms_base.html',): + if e.args != ("feincms_base.html",): raise def test_21_copy_content(self): @@ -1133,8 +1139,7 @@ def test_23_navigation_extension(self): self.assertEqual(len(page.extended_navigation()), 0) - page.navigation_extension =\ - 'testapp.navigation_extensions.PassthroughExtension' + page.navigation_extension = "testapp.navigation_extensions.PassthroughExtension" page2 = Page.objects.get(pk=2) page2.active = True @@ -1143,16 +1148,15 @@ def test_23_navigation_extension(self): self.assertEqual(list(page.extended_navigation()), [page2]) - page.navigation_extension =\ - 'testapp.navigation_extensions.ThisExtensionDoesNotExist' + page.navigation_extension = ( + "testapp.navigation_extensions.ThisExtensionDoesNotExist" + ) self.assertEqual(len(page.extended_navigation()), 1) - page.navigation_extension =\ - 'testapp.navigation_extensions.PretenderExtension' + page.navigation_extension = "testapp.navigation_extensions.PretenderExtension" - self.assertEqual( - page.extended_navigation()[0].get_absolute_url(), '/asdsa/') + self.assertEqual(page.extended_navigation()[0].get_absolute_url(), "/asdsa/") def test_24_admin_redirects(self): self.create_default_page_set() @@ -1160,15 +1164,13 @@ def test_24_admin_redirects(self): page = Page.objects.get(pk=1) response = self.create_page_through_admincontent(page, _continue=1) - self.assertRedirects( - response, - reverse('admin:page_page_change', args=(1,))) + self.assertRedirects(response, reverse("admin:page_page_change", args=(1,))) response = self.create_page_through_admincontent(page, _addanother=1) - self.assertRedirects(response, '/admin/page/page/add/') + self.assertRedirects(response, "/admin/page/page/add/") response = self.create_page_through_admincontent(page) - self.assertRedirects(response, '/admin/page/page/') + self.assertRedirects(response, "/admin/page/page/") def test_25_applicationcontent(self): self.create_default_page_set() @@ -1179,134 +1181,131 @@ def test_25_applicationcontent(self): page = Page.objects.get(pk=2) page.active = True - page.template_key = 'theother' + page.template_key = "theother" page.save() # Should not be published because the page has no application contents # and should therefore not catch anything below it. - self.is_published(page1.get_absolute_url() + 'anything/', False) + self.is_published(page1.get_absolute_url() + "anything/", False) page.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='testapp.applicationcontent_urls') + region="main", ordering=0, urlconf_path="testapp.applicationcontent_urls" + ) + self.assertContains(self.client.get(page.get_absolute_url()), "module_root") self.assertContains( - self.client.get(page.get_absolute_url()), - 'module_root') - self.assertContains( - self.client.get(page.get_absolute_url() + 'args_test/abc/def/'), - 'abc-def') + self.client.get(page.get_absolute_url() + "args_test/abc/def/"), "abc-def" + ) self.assertContains( - self.client.get(page.get_absolute_url() + 'kwargs_test/abc/def/'), - 'def-abc') + self.client.get(page.get_absolute_url() + "kwargs_test/abc/def/"), "def-abc" + ) - response = self.client.get( - page.get_absolute_url() + 'full_reverse_test/') - self.assertContains(response, 'home:/test-page/test-child-page/') + response = self.client.get(page.get_absolute_url() + "full_reverse_test/") + self.assertContains(response, "home:/test-page/test-child-page/") self.assertContains( - response, - 'args:/test-page/test-child-page/args_test/xy/zzy/') - self.assertContains(response, 'base:/test/') - self.assertContains(response, 'homeas:/test-page/test-child-page/') + response, "args:/test-page/test-child-page/args_test/xy/zzy/" + ) + self.assertContains(response, "base:/test/") + self.assertContains(response, "homeas:/test-page/test-child-page/") self.assertEqual( - app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - '/test-page/test-child-page/') + app_reverse("ac_module_root", "testapp.applicationcontent_urls"), + "/test-page/test-child-page/", + ) - if hasattr(self, 'assertNumQueries'): + if hasattr(self, "assertNumQueries"): self.assertNumQueries( 0, lambda: app_reverse( - 'ac_module_root', 'testapp.applicationcontent_urls')) + "ac_module_root", "testapp.applicationcontent_urls" + ), + ) # This should not raise self.assertEqual( - self.client.get( - page.get_absolute_url() + 'notexists/' - ).status_code, 404) + self.client.get(page.get_absolute_url() + "notexists/").status_code, 404 + ) self.assertContains( - self.client.get(page.get_absolute_url() + 'fragment/'), - 'some things') + self.client.get(page.get_absolute_url() + "fragment/"), + 'some things', + ) self.assertRedirects( - self.client.get(page.get_absolute_url() + 'redirect/'), - 'http://testserver' + page.get_absolute_url()) + self.client.get(page.get_absolute_url() + "redirect/"), + "http://testserver" + page.get_absolute_url(), + ) self.assertEqual( - app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - page.get_absolute_url()) + app_reverse("ac_module_root", "testapp.applicationcontent_urls"), + page.get_absolute_url(), + ) - response = self.client.get(page.get_absolute_url() + 'response/') - self.assertContains(response, 'Anything') + response = self.client.get(page.get_absolute_url() + "response/") + self.assertContains(response, "Anything") # Ensure response has been wrapped - self.assertContains(response, '

    Main content

    ') + self.assertContains(response, "

    Main content

    ") # Test standalone behavior self.assertEqual( self.client.get( - page.get_absolute_url() + 'response/', - HTTP_X_REQUESTED_WITH='XMLHttpRequest').content, - self.client.get( - page.get_absolute_url() + 'response_decorated/').content) + page.get_absolute_url() + "response/", + HTTP_X_REQUESTED_WITH="XMLHttpRequest", + ).content, + self.client.get(page.get_absolute_url() + "response_decorated/").content, + ) page1.applicationcontent_set.create( - region='main', - ordering=0, - urlconf_path='whatever') + region="main", ordering=0, urlconf_path="whatever" + ) - response = self.client.get( - page.get_absolute_url() + 'alias_reverse_test/') - self.assertContains(response, 'home:/test-page/') - self.assertContains(response, 'args:/test-page/args_test/xy/zzy/') - self.assertContains(response, 'base:/test/') + response = self.client.get(page.get_absolute_url() + "alias_reverse_test/") + self.assertContains(response, "home:/test-page/") + self.assertContains(response, "args:/test-page/args_test/xy/zzy/") + self.assertContains(response, "base:/test/") self.assertEqual( - app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - '/test-page/test-child-page/') - self.assertEqual( - app_reverse('ac_module_root', 'whatever'), - '/test-page/') + app_reverse("ac_module_root", "testapp.applicationcontent_urls"), + "/test-page/test-child-page/", + ) + self.assertEqual(app_reverse("ac_module_root", "whatever"), "/test-page/") page.applicationcontent_set.get( - urlconf_path='testapp.applicationcontent_urls').delete() + urlconf_path="testapp.applicationcontent_urls" + ).delete() - self.assertEqual( - app_reverse('ac_module_root', 'whatever'), - '/test-page/') + self.assertEqual(app_reverse("ac_module_root", "whatever"), "/test-page/") # Ensure ApplicationContent's admin_fields support works properly self.login() - response = self.client.get( - reverse('admin:page_page_change', args=(page1.id,)) - ) + response = self.client.get(reverse("admin:page_page_change", args=(page1.id,))) - self.assertContains(response, 'exclusive_subpages') - self.assertContains(response, 'custom_field') + self.assertContains(response, "exclusive_subpages") + self.assertContains(response, "custom_field") # Check if admin_fields get populated correctly app_ct = page1.applicationcontent_set.all()[0] - app_ct.parameters =\ - '{"custom_field":"val42", "exclusive_subpages": false}' + app_ct.parameters = '{"custom_field":"val42", "exclusive_subpages": false}' app_ct.save() - response = self.client.get( - reverse('admin:page_page_change', args=(page1.id,)) - ) - self.assertContains(response, 'val42') + response = self.client.get(reverse("admin:page_page_change", args=(page1.id,))) + self.assertContains(response, "val42") def test_26_page_form_initial(self): self.create_default_page_set() self.login() - self.assertEqual(self.client.get( - '/admin/page/page/add/?translation_of=1&lang=de' - ).status_code, 200) - self.assertEqual(self.client.get( - '/admin/page/page/add/?parent=1' - ).status_code, 200) - self.assertEqual(self.client.get( - '/admin/page/page/add/?parent=2' - ).status_code, 200) + self.assertEqual( + self.client.get( + "/admin/page/page/add/?translation_of=1&lang=de" + ).status_code, + 200, + ) + self.assertEqual( + self.client.get("/admin/page/page/add/?parent=1").status_code, 200 + ) + self.assertEqual( + self.client.get("/admin/page/page/add/?parent=2").status_code, 200 + ) def test_27_cached_url_clash(self): self.create_default_page_set() @@ -1314,15 +1313,15 @@ def test_27_cached_url_clash(self): page1 = Page.objects.get(pk=1) page2 = Page.objects.get(pk=2) - page1.override_url = '/' + page1.override_url = "/" page1.active = True page1.save() self.login() self.assertContains( - self.create_page_through_admincontent( - page2, active=True, override_url='/'), - 'already taken by') + self.create_page_through_admincontent(page2, active=True, override_url="/"), + "already taken by", + ) def test_28_applicationcontent_reverse(self): self.create_default_page_set() @@ -1332,48 +1331,49 @@ def test_28_applicationcontent_reverse(self): page = Page.objects.get(pk=2) page.active = True - page.template_key = 'theother' + page.template_key = "theother" page.save() page.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='testapp.applicationcontent_urls') + region="main", ordering=0, urlconf_path="testapp.applicationcontent_urls" + ) # test app_reverse self.assertEqual( - app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - page.get_absolute_url()) + app_reverse("ac_module_root", "testapp.applicationcontent_urls"), + page.get_absolute_url(), + ) # when specific applicationcontent exists more then once reverse should # return the URL of the first (ordered by primary key) page. self.login() + self.create_page_through_admin(title="Home DE", language="de", active=True) + page_de = Page.objects.get(title="Home DE") self.create_page_through_admin( - title='Home DE', language='de', active=True) - page_de = Page.objects.get(title='Home DE') - self.create_page_through_admin( - title='Child 1 DE', language='de', parent=page_de.id, active=True) - page_de_1 = Page.objects.get(title='Child 1 DE') + title="Child 1 DE", language="de", parent=page_de.id, active=True + ) + page_de_1 = Page.objects.get(title="Child 1 DE") page_de_1.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='testapp.applicationcontent_urls') + region="main", ordering=0, urlconf_path="testapp.applicationcontent_urls" + ) page.active = False page.save() - settings.TEMPLATE_DIRS = ( - os.path.join(os.path.dirname(__file__), 'templates'), - ) + settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), "templates"),) self.client.get(page_de_1.get_absolute_url()) self.assertEqual( - app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - page_de_1.get_absolute_url()) + app_reverse("ac_module_root", "testapp.applicationcontent_urls"), + page_de_1.get_absolute_url(), + ) page.active = True page.save() self.client.get(page1.get_absolute_url()) self.assertEqual( - app_reverse('ac_module_root', 'testapp.applicationcontent_urls'), - page.get_absolute_url()) + app_reverse("ac_module_root", "testapp.applicationcontent_urls"), + page.get_absolute_url(), + ) def test_29_medialibrary_admin(self): self.create_default_page_set() @@ -1381,56 +1381,59 @@ def test_29_medialibrary_admin(self): page = Page.objects.get(pk=1) - mediafile = MediaFile.objects.create(file='somefile.jpg') + mediafile = MediaFile.objects.create(file="somefile.jpg") page.mediafilecontent_set.create( - mediafile=mediafile, - region='main', - type='default', - ordering=1) + mediafile=mediafile, region="main", type="default", ordering=1 + ) self.assertContains( - self.client.get('/admin/medialibrary/mediafile/'), - 'somefile.jpg') + self.client.get("/admin/medialibrary/mediafile/"), "somefile.jpg" + ) import zipfile - zf = zipfile.ZipFile('test.zip', 'w') + + zf = zipfile.ZipFile("test.zip", "w") for i in range(10): - zf.writestr('test%d.txt' % i, 'test%d' % i) + zf.writestr("test%d.txt" % i, "test%d" % i) zf.close() - with open('test.zip', 'rb') as handle: + with open("test.zip", "rb") as handle: response = self.client.post( - '/admin/medialibrary/mediafile/mediafile-bulk-upload/', { - 'data': handle, - }) - self.assertRedirects(response, '/admin/medialibrary/mediafile/') + "/admin/medialibrary/mediafile/mediafile-bulk-upload/", {"data": handle} + ) + self.assertRedirects(response, "/admin/medialibrary/mediafile/") self.assertEqual( MediaFile.objects.count(), 11, - "Upload of media files with ZIP does not work") + "Upload of media files with ZIP does not work", + ) dn = os.path.dirname path = os.path.join( - dn(dn(dn(dn(__file__)))), 'docs', 'images', 'tree_editor.png') + dn(dn(dn(dn(__file__)))), "docs", "images", "tree_editor.png" + ) - with open(path, 'rb') as handle: - response = self.client.post('/admin/medialibrary/mediafile/add/', { - 'file': handle, - 'translations-TOTAL_FORMS': 0, - 'translations-INITIAL_FORMS': 0, - 'translations-MAX_NUM_FORMS': 10, - }) - self.assertRedirects(response, '/admin/medialibrary/mediafile/') + with open(path, "rb") as handle: + response = self.client.post( + "/admin/medialibrary/mediafile/add/", + { + "file": handle, + "translations-TOTAL_FORMS": 0, + "translations-INITIAL_FORMS": 0, + "translations-MAX_NUM_FORMS": 10, + }, + ) + self.assertRedirects(response, "/admin/medialibrary/mediafile/") self.assertContains( - self.client.get('/admin/medialibrary/mediafile/'), - '100x100') + self.client.get("/admin/medialibrary/mediafile/"), "100x100" + ) - stats = list(MediaFile.objects.values_list('type', flat=True)) + stats = list(MediaFile.objects.values_list("type", flat=True)) self.assertEqual(len(stats), 12) - self.assertEqual(stats.count('image'), 2) - self.assertEqual(stats.count('txt'), 10) + self.assertEqual(stats.count("image"), 2) + self.assertEqual(stats.count("txt"), 10) def test_30_context_processors(self): self.create_default_page_set() @@ -1439,20 +1442,20 @@ def test_30_context_processors(self): request = Empty() request.GET = {} request.META = {} - request.method = 'GET' - request.path = request.path_info = '/test-page/test-child-page/abcdef/' - request.get_full_path = lambda: '/test-page/test-child-page/abcdef/' + request.method = "GET" + request.path = request.path_info = "/test-page/test-child-page/abcdef/" + request.get_full_path = lambda: "/test-page/test-child-page/abcdef/" ctx = add_page_if_missing(request) - self.assertEqual(ctx['feincms_page'], request._feincms_page) + self.assertEqual(ctx["feincms_page"], request._feincms_page) def test_31_sites_framework_associating_with_single_site(self): self.login() - site_2 = Site.objects.create(name='site 2', domain='2.example.com') - self.create_page_through_admin( - 'site 1 homepage', override_url='/', active=True) + site_2 = Site.objects.create(name="site 2", domain="2.example.com") + self.create_page_through_admin("site 1 homepage", override_url="/", active=True) self.create_page_through_admin( - 'site 2 homepage', override_url='/', site=site_2.id, active=True) + "site 2 homepage", override_url="/", site=site_2.id, active=True + ) self.assertEqual(Page.objects.count(), 2) self.assertEqual(Page.objects.active().count(), 1) @@ -1465,145 +1468,141 @@ def test_32_applicationcontent_inheritance20(self): page = Page.objects.get(pk=2) page.active = True - page.template_key = 'theother' + page.template_key = "theother" page.save() # Should not be published because the page has no application contents # and should therefore not catch anything below it. - self.is_published(page1.get_absolute_url() + 'anything/', False) + self.is_published(page1.get_absolute_url() + "anything/", False) page.applicationcontent_set.create( - region='main', ordering=0, - urlconf_path='testapp.applicationcontent_urls') + region="main", ordering=0, urlconf_path="testapp.applicationcontent_urls" + ) page.rawcontent_set.create( - region='main', ordering=1, text='some_main_region_text') + region="main", ordering=1, text="some_main_region_text" + ) page.rawcontent_set.create( - region='sidebar', ordering=0, text='some_sidebar_region_text') + region="sidebar", ordering=0, text="some_sidebar_region_text" + ) - self.assertContains(self.client.get(page.get_absolute_url()), - 'module_root') + self.assertContains(self.client.get(page.get_absolute_url()), "module_root") - response = self.client.get(page.get_absolute_url() + 'inheritance20/') - self.assertContains(response, 'a content 42') - self.assertContains(response, 'b content') - self.assertNotContains(response, 'some_main_region_text') - self.assertContains(response, 'some_sidebar_region_text') - self.assertNotContains(response, 'some content outside') + response = self.client.get(page.get_absolute_url() + "inheritance20/") + self.assertContains(response, "a content 42") + self.assertContains(response, "b content") + self.assertNotContains(response, "some_main_region_text") + self.assertContains(response, "some_sidebar_region_text") + self.assertNotContains(response, "some content outside") - response = self.client.get( - page.get_absolute_url() + 'inheritance20_unpack/') - self.assertContains(response, 'a content 43') - self.assertIn('yabba dabba', response['cache-control']) + response = self.client.get(page.get_absolute_url() + "inheritance20_unpack/") + self.assertContains(response, "a content 43") + self.assertIn("yabba dabba", response["cache-control"]) def test_33_preview(self): self.create_default_page_set() page = Page.objects.get(pk=1) - page.template_key = 'theother' + page.template_key = "theother" page.save() - page.rawcontent_set.create( - region='main', - ordering=0, - text='Example content') + page.rawcontent_set.create(region="main", ordering=0, text="Example content") self.login() - self.assertEqual( - self.client.get(page.get_absolute_url()).status_code, 404) + self.assertEqual(self.client.get(page.get_absolute_url()).status_code, 404) self.assertContains( - self.client.get('%s_preview/%s/' % ( - page.get_absolute_url(), - page.pk), - ), - 'Example content') + self.client.get("%s_preview/%s/" % (page.get_absolute_url(), page.pk)), + "Example content", + ) def test_34_access(self): self.create_default_page_set() page = Page.objects.get(pk=1) - page.override_url = '/something/' + page.override_url = "/something/" page.save() Page.objects.update(active=True) self.login() self.create_page_through_admin( - title='redirect page', - override_url='/', + title="redirect page", + override_url="/", redirect_to=page.get_absolute_url(), - active=True) + active=True, + ) # / -> redirect to /something/ - r = self.client.get('/') + r = self.client.get("/") self.assertRedirects(r, page.get_absolute_url()) # /something/ should work r = self.client.get(page.override_url) self.assertEqual(r.status_code, 200) # /foo not existant -> 404 - r = self.client.get('/foo/') + r = self.client.get("/foo/") self.assertEqual(r.status_code, 404) def test_35_access_with_extra_path(self): self.login() self.create_page( - title='redirect again', - override_url='/', - redirect_to='/somewhere/', - active=True) - self.create_page(title='somewhere', active=True) - - r = self.client.get('/') - self.assertRedirects(r, '/somewhere/') - r = self.client.get('/dingdong/') + title="redirect again", + override_url="/", + redirect_to="/somewhere/", + active=True, + ) + self.create_page(title="somewhere", active=True) + + r = self.client.get("/") + self.assertRedirects(r, "/somewhere/") + r = self.client.get("/dingdong/") self.assertEqual(r.status_code, 404) old = feincms_settings.FEINCMS_ALLOW_EXTRA_PATH feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = True - r = self.client.get('/') - self.assertRedirects(r, '/somewhere/') - r = self.client.get('/dingdong/') + r = self.client.get("/") + self.assertRedirects(r, "/somewhere/") + r = self.client.get("/dingdong/") self.assertEqual(r.status_code, 404) feincms_settings.FEINCMS_ALLOW_EXTRA_PATH = old def test_36_sitemaps(self): - response = self.client.get('/sitemap.xml') - self.assertContains(response, '', status_code=200) + response = self.client.get("/sitemap.xml") + self.assertNotContains(response, "", status_code=200) page = Page.objects.get() page.active = True page.in_navigation = True page.save() - response = self.client.get('/sitemap.xml') - self.assertContains(response, '', status_code=200) + response = self.client.get("/sitemap.xml") + self.assertContains(response, "", status_code=200) def test_37_invalid_parent(self): self.create_default_page_set() - page1, page2 = list(Page.objects.order_by('id')) + page1, page2 = list(Page.objects.order_by("id")) page1.parent = page1 self.assertRaises(InvalidMove, page1.save) - self.create_page('Page 3', parent=page2) - page1, page2, page3 = list(Page.objects.order_by('id')) + self.create_page("Page 3", parent=page2) + page1, page2, page3 = list(Page.objects.order_by("id")) page1.parent = page3 self.assertRaises(InvalidMove, page1.save) def test_38_invalid_template(self): page = Page() - page.template_key = 'test' - self.assertEqual(page.template.key, 'base') + page.template_key = "test" + self.assertEqual(page.template.key, "base") def test_39_navigationgroups(self): self.create_default_page_set() - page1, page2 = list(Page.objects.order_by('id')) + page1, page2 = list(Page.objects.order_by("id")) page1.active = True page1.in_navigation = True @@ -1611,84 +1610,77 @@ def test_39_navigationgroups(self): page2.active = True page2.in_navigation = True - page2.navigation_group = 'footer' + page2.navigation_group = "footer" page2.save() t = template.Template( - ''' + """ {% load feincms_page_tags %} {% feincms_nav feincms_page level=1 depth=10 group='default' as nav %} {% for p in nav %}{{ p.get_absolute_url }},{% endfor %} - ''' + """ ) - str = t.render(template.Context({ - 'feincms_page': page1, - })) + str = t.render(template.Context({"feincms_page": page1})) - self.assertEqual(str.strip(), '/test-page/,') + self.assertEqual(str.strip(), "/test-page/,") t = template.Template( - ''' + """ {% load feincms_page_tags %} {% feincms_nav feincms_page level=1 depth=10 group='footer' as nav %} {% for p in nav %}{{ p.get_absolute_url }},{% endfor %} - ''' + """ ) - str = t.render(template.Context({ - 'feincms_page': page1, - })) + str = t.render(template.Context({"feincms_page": page1})) - self.assertEqual(str.strip(), '/test-page/test-child-page/,') + self.assertEqual(str.strip(), "/test-page/test-child-page/,") def test_40_page_is_active(self): self.create_default_page_set() - page1, page2 = list(Page.objects.order_by('id')) + page1, page2 = list(Page.objects.order_by("id")) - self.assertTrue(feincms_page_tags.page_is_active( - {'feincms_page': page1}, page1)) - self.assertTrue(feincms_page_tags.page_is_active( - {'feincms_page': page2}, page1)) - self.assertFalse(feincms_page_tags.page_is_active( - {'feincms_page': page1}, page2)) + self.assertTrue( + feincms_page_tags.page_is_active({"feincms_page": page1}, page1) + ) + self.assertTrue( + feincms_page_tags.page_is_active({"feincms_page": page2}, page1) + ) + self.assertFalse( + feincms_page_tags.page_is_active({"feincms_page": page1}, page2) + ) - p = PagePretender( - title='bla', - slug='bla', - url='/test-page/whatsup/') + p = PagePretender(title="bla", slug="bla", url="/test-page/whatsup/") - self.assertTrue(feincms_page_tags.page_is_active( - {}, p, path='/test-page/whatsup/test/')) - self.assertFalse(feincms_page_tags.page_is_active( - {}, p, path='/test-page/')) + self.assertTrue( + feincms_page_tags.page_is_active({}, p, path="/test-page/whatsup/test/") + ) + self.assertFalse(feincms_page_tags.page_is_active({}, p, path="/test-page/")) - self.assertTrue(feincms_page_tags.page_is_active( - {'feincms_page': page1}, p, path='/test-page/whatsup/test/')) - self.assertFalse(feincms_page_tags.page_is_active( - {'feincms_page': page2}, p, path='/test-page/')) + self.assertTrue( + feincms_page_tags.page_is_active( + {"feincms_page": page1}, p, path="/test-page/whatsup/test/" + ) + ) + self.assertFalse( + feincms_page_tags.page_is_active( + {"feincms_page": page2}, p, path="/test-page/" + ) + ) def test_41_templatecontent(self): page = self.create_page(active=True) page.templatecontent_set.create( - region='main', - ordering=10, - template='templatecontent_1.html', + region="main", ordering=10, template="templatecontent_1.html" ) # The empty form contains the template option. self.login() self.assertContains( - self.client.get( - reverse('admin:page_page_change', args=(page.id,)) - ), - '') + self.client.get(reverse("admin:page_page_change", args=(page.id,))), + '', + ) response = self.client.get(page.get_absolute_url()) - self.assertContains( - response, - 'TemplateContent_1', - ) - self.assertContains( - response, - '#42#', - ) + self.assertContains(response, "TemplateContent_1") + self.assertContains(response, "#42#") diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index b567daba6..71ac0bd4e 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -39,47 +39,40 @@ class ModelsTest(TestCase): def test_region(self): # Creation should not fail - r = Region('region', 'region title') + r = Region("region", "region title") t = Template( - 'base template', - 'base.html', - ( - ('region', 'region title'), - Region('region2', 'region2 title'), - ), + "base template", + "base.html", + (("region", "region title"), Region("region2", "region2 title")), ) # I'm not sure whether this test tests anything at all self.assertEqual(r.key, t.regions[0].key) - self.assertEqual(force_text(r), 'region title') + self.assertEqual(force_text(r), "region title") class UtilsTest(TestCase): def test_get_object(self): - self.assertRaises( - AttributeError, lambda: get_object('feincms.does_not_exist')) - self.assertRaises( - ImportError, lambda: get_object('feincms.does_not_exist.fn')) + self.assertRaises(AttributeError, lambda: get_object("feincms.does_not_exist")) + self.assertRaises(ImportError, lambda: get_object("feincms.does_not_exist.fn")) - self.assertEqual(get_object, get_object('feincms.utils.get_object')) + self.assertEqual(get_object, get_object("feincms.utils.get_object")) def test_shorten_string(self): string = shorten_string( - "Der Wolf und die Grossmutter assen im Wald zu mittag", - 15, ellipsis="_") - self.assertEqual(string, 'Der Wolf und_ag') + "Der Wolf und die Grossmutter assen im Wald zu mittag", 15, ellipsis="_" + ) + self.assertEqual(string, "Der Wolf und_ag") self.assertEqual(len(string), 15) string = shorten_string( - "Haenschen-Klein, ging allein, in den tiefen Wald hinein", - 15) - self.assertEqual(string, 'Haenschen \u2026 ein') + "Haenschen-Klein, ging allein, in den tiefen Wald hinein", 15 + ) + self.assertEqual(string, "Haenschen \u2026 ein") self.assertEqual(len(string), 15) - string = shorten_string( - 'Badgerbadgerbadgerbadgerbadger', - 10, ellipsis='-') - self.assertEqual(string, 'Badger-ger') + string = shorten_string("Badgerbadgerbadgerbadgerbadger", 10, ellipsis="-") + self.assertEqual(string, "Badger-ger") self.assertEqual(len(string), 10) @@ -88,7 +81,7 @@ class TimezoneTest(TestCase): def test_granular_now_dst_transition(self): # Should not raise an exception d = datetime(2016, 10, 30, 2, 10) - tz = pytz.timezone('Europe/Copenhagen') + tz = pytz.timezone("Europe/Copenhagen") granular_now(d, default_tz=tz) def test_granular_now_rounding(self): @@ -97,4 +90,5 @@ def test_granular_now_rounding(self): self.assertEqual(d.hour, g.hour) self.assertEqual(10, g.minute) + # ------------------------------------------------------------------------ diff --git a/tests/testapp/tests/utils.py b/tests/testapp/tests/utils.py index 31ca0639e..5d52b4f5f 100644 --- a/tests/testapp/tests/utils.py +++ b/tests/testapp/tests/utils.py @@ -8,6 +8,7 @@ class MockDatetime(datetime.datetime): @classmethod def now(cls): return datetime.datetime(2012, 6, 1) + return MockDatetime @@ -16,4 +17,5 @@ class MockDate(datetime.date): @classmethod def today(cls): return datetime.date(2012, 6, 1) + return MockDate diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index f1dbcc4a9..df1d6791a 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -11,27 +11,20 @@ from feincms.module.page.sitemap import PageSitemap -sitemaps = {'pages': PageSitemap} +sitemaps = {"pages": PageSitemap} admin.autodiscover() urlpatterns = [ - url(r'^admin/', admin.site.urls), - + url(r"^admin/", admin.site.urls), url( - r'^media/(?P.*)$', + r"^media/(?P.*)$", serve, - {'document_root': os.path.join(os.path.dirname(__file__), 'media/')}, + {"document_root": os.path.join(os.path.dirname(__file__), "media/")}, ), - - url( - r'^sitemap\.xml$', - sitemap, - {'sitemaps': sitemaps}, - ), - - url(r'', include('feincms.contrib.preview.urls')), - url(r'', include('feincms.urls')), + url(r"^sitemap\.xml$", sitemap, {"sitemaps": sitemaps}), + url(r"", include("feincms.contrib.preview.urls")), + url(r"", include("feincms.urls")), ] urlpatterns += staticfiles_urlpatterns() diff --git a/tox.ini b/tox.ini index 3f96dd417..cf21779ef 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,11 @@ basepython = python3 [testenv:style] deps = + black flake8 changedir = {toxinidir} commands = + black feincms tests setup.py flake8 . skip_install = true From 8c94fb0a429d90b5557aa5649e351d3922d92c48 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 1 Feb 2019 18:28:05 +0100 Subject: [PATCH 1423/1590] Django@master dropped the staticfiles template tag library --- feincms/module/page/modeladmins.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 4a6847537..fe2050daf 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -9,7 +9,6 @@ from django.conf import settings as django_settings from django.core.exceptions import PermissionDenied from django.contrib.contenttypes.models import ContentType -from django.contrib.staticfiles.templatetags.staticfiles import static from django.contrib import admin from django.contrib import messages from django.http import HttpResponseRedirect @@ -21,6 +20,12 @@ except ImportError: from django.core.urlresolvers import reverse +try: + from django.contrib.staticfiles.templatetags.staticfiles import static +except ImportError: + # Newer Django versions. + from django.templatetags.static import static + from feincms import ensure_completely_loaded from feincms import settings from feincms.admin import item_editor, tree_editor From 54a4a2eb32763c8ed2b9ddb66cb92195564edf86 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 1 Feb 2019 18:31:53 +0100 Subject: [PATCH 1424/1590] FeinCMS v1.16.0 --- CHANGELOG.rst | 8 +++++++- feincms/__init__.py | 2 +- setup.py | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5a54bc50d..11a949cb4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,12 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ +`v1.16.0`_ (2019-02-01) +~~~~~~~~~~~~~~~~~~~~~~~ + - Reformatted everything using black. +- Added a fallback import for the ``staticfiles`` template tag library + which will be gone in Django 3.0. `v1.15.0`_ (2018-12-21) @@ -59,4 +64,5 @@ Change log .. _v1.14.0: https://github.com/feincms/feincms/compare/v1.13.0...v1.14.0 .. _v1.15.0: https://github.com/feincms/feincms/compare/v1.14.0...v1.15.0 -.. _Next version: https://github.com/feincms/feincms/compare/v1.15.0...master +.. _v1.16.0: https://github.com/feincms/feincms/compare/v1.15.0...v1.16.0 +.. _Next version: https://github.com/feincms/feincms/compare/v1.16.0...master diff --git a/feincms/__init__.py b/feincms/__init__.py index 308b8f1cd..68ac06ad5 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -VERSION = (1, 15, 0) +VERSION = (1, 16, 0) __version__ = ".".join(map(str, VERSION)) diff --git a/setup.py b/setup.py index a9fdce423..f969f4cd6 100755 --- a/setup.py +++ b/setup.py @@ -49,6 +49,7 @@ def read(filename): "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development", "Topic :: Software Development :: Libraries :: Application Frameworks", From 17de1d0371bd491954bd26c4ddacf555467353e2 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 1 Feb 2019 18:42:45 +0100 Subject: [PATCH 1425/1590] Various compatibility fixes --- feincms/admin/tree_editor.py | 7 ++++++- feincms/contrib/fields.py | 2 +- feincms/module/medialibrary/models.py | 2 +- feincms/templates/admin/feincms/_regions_js.html | 2 +- feincms/templates/admin/feincms/item_editor.html | 2 +- feincms/templates/admin/feincms/load-jquery.include | 2 +- feincms/templates/admin/feincms/tree_editor.html | 2 +- tests/testapp/settings.py | 2 +- 8 files changed, 13 insertions(+), 8 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 2eecb1484..9e718b714 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -11,7 +11,6 @@ from django.contrib.admin.views import main from django.contrib.admin.actions import delete_selected from django.contrib.auth import get_permission_codename -from django.contrib.staticfiles.templatetags.staticfiles import static from django.db.models import Q from django.http import ( HttpResponse, @@ -31,6 +30,12 @@ from feincms import settings from feincms.extensions import ExtensionModelAdmin +try: + # Django<3 + from django.contrib.staticfiles.templatetags.staticfiles import static +except ImportError: + from django.templatetags.static import static + logger = logging.getLogger(__name__) diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index bf8b8ed3b..89f0b2639 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -69,7 +69,7 @@ def to_python(self, value): assert value is None return {} - def from_db_value(self, value, expression, connection, context): + def from_db_value(self, value, expression, connection, context=None): return self.to_python(value) def get_prep_value(self, value): diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 424abd327..1a2d2ba08 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -143,7 +143,7 @@ def register_filetypes(cls, *types): cls.filetypes[0:0] = types choices = [t[0:2] for t in cls.filetypes] cls.filetypes_dict = dict(choices) - cls._meta.get_field("type").choices[:] = choices + cls._meta.get_field("type").choices = choices def __init__(self, *args, **kwargs): super(MediaFileBase, self).__init__(*args, **kwargs) diff --git a/feincms/templates/admin/feincms/_regions_js.html b/feincms/templates/admin/feincms/_regions_js.html index adebda187..2d39f7eb3 100644 --- a/feincms/templates/admin/feincms/_regions_js.html +++ b/feincms/templates/admin/feincms/_regions_js.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% endblock %} From 7687efc7b2362b00a63dbda8c40cbfa5b9875348 Mon Sep 17 00:00:00 2001 From: Arkadiy Korotaev Date: Tue, 16 Mar 2021 20:48:40 +0100 Subject: [PATCH 1467/1590] fix(JS): Use default form.action for django3.1 (where this attribute is absent) --- feincms/static/feincms/item_editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index a4d25f93b..2a2c4de7f 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -496,7 +496,8 @@ if (!Array.prototype.indexOf) { $('form').submit(function(){ give_ordering_to_content_types(); var form = $(this); - form.attr('action', form.attr('action')+window.location.hash); + var action = form.attr("action") || ""; + form.attr('action', action + window.location.hash); return true; }); From 576b252bff6fdc808be9a0eb70768c72febf42ac Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 22 Mar 2021 20:19:16 +0100 Subject: [PATCH 1468/1590] Format the code to fix line length errors --- feincms/content/filer/models.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/feincms/content/filer/models.py b/feincms/content/filer/models.py index e2eaf1ea4..2feba4578 100644 --- a/feincms/content/filer/models.py +++ b/feincms/content/filer/models.py @@ -50,7 +50,9 @@ def render(self, **kwargs): ) class FilerFileContent(ContentWithFilerFile): - mediafile = FilerFileField(verbose_name=_("file"), related_name="+", on_delete=models.CASCADE) + mediafile = FilerFileField( + verbose_name=_("file"), related_name="+", on_delete=models.CASCADE + ) file_type = "file" type = "download" @@ -86,7 +88,9 @@ class FilerImageContent(ContentWithFilerFile): must_always_publish_copyright, date_taken, file, id, is_public, url """ - mediafile = FilerImageField(verbose_name=_("image"), related_name="+", on_delete=models.CASCADE) + mediafile = FilerImageField( + verbose_name=_("image"), related_name="+", on_delete=models.CASCADE + ) caption = models.CharField(_("caption"), max_length=1000, blank=True) url = models.CharField(_("URL"), max_length=1000, blank=True) From 31712d8e54a9af46b655ae51701771bc8dcfb5c1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 22 Mar 2021 20:19:50 +0100 Subject: [PATCH 1469/1590] No need to run flake8 checks inside each job --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f09bcd3ad..4e3cab945 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,6 +59,6 @@ matrix: - env: REQ="https://github.com/django/django/archive/master.zip django-mptt" install: - pip install -U pip wheel setuptools - - pip install $REQ Pillow flake8 pytz six + - pip install $REQ Pillow pytz six - python setup.py install -script: "cd tests && ./manage.py test testapp && cd .. && flake8 ." +script: "cd tests && ./manage.py test testapp" From 8f7cb92c4118e9bead092b35200c338fb2926f3c Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 22 Mar 2021 20:56:46 +0100 Subject: [PATCH 1470/1590] Reformat everything, add GitHub action workflows for testing --- .editorconfig | 12 + .eslintrc.js | 19 + .github/workflows/tests.yml | 50 + .gitignore | 1 + .prettierignore | 3 + CHANGELOG.rst | 6 + README.rst | 6 +- docs/conf.py | 99 +- feincms/__init__.py | 7 +- feincms/_internal.py | 1 + feincms/admin/__init__.py | 3 +- feincms/admin/filters.py | 2 +- feincms/admin/tree_editor.py | 10 +- feincms/content/application/models.py | 9 +- feincms/content/contactform/__init__.py | 1 + feincms/content/filer/models.py | 3 +- feincms/content/medialibrary/models.py | 1 + feincms/contrib/fields.py | 7 +- feincms/contrib/tagging.py | 5 +- feincms/default_settings.py | 1 + feincms/extensions/__init__.py | 3 +- feincms/extensions/base.py | 4 +- feincms/extensions/changedate.py | 2 +- feincms/extensions/datepublisher.py | 2 +- feincms/extensions/translations.py | 2 +- .../commands/medialibrary_to_filer.py | 5 +- feincms/management/commands/rebuild_mptt.py | 1 + feincms/models.py | 8 +- feincms/module/extensions/changedate.py | 1 + feincms/module/extensions/ct_tracker.py | 1 + feincms/module/extensions/datepublisher.py | 1 + feincms/module/extensions/featured.py | 1 + feincms/module/extensions/seo.py | 1 + feincms/module/extensions/translations.py | 1 + feincms/module/medialibrary/__init__.py | 1 + feincms/module/medialibrary/admin.py | 3 +- feincms/module/medialibrary/fields.py | 5 +- feincms/module/medialibrary/forms.py | 2 +- feincms/module/medialibrary/modeladmins.py | 8 +- feincms/module/medialibrary/models.py | 4 +- feincms/module/medialibrary/zip.py | 2 +- feincms/module/page/admin.py | 4 +- feincms/module/page/extensions/navigation.py | 6 +- feincms/module/page/forms.py | 3 +- feincms/module/page/modeladmins.py | 9 +- feincms/module/page/models.py | 4 +- feincms/module/page/sitemap.py | 2 +- feincms/signals.py | 1 + feincms/static/feincms/item_editor.css | 304 +++-- feincms/static/feincms/item_editor.js | 1160 +++++++++-------- feincms/static/feincms/tree_editor.css | 33 +- feincms/static/feincms/tree_editor.js | 765 ++++++----- .../templatetags/applicationcontent_tags.py | 1 + feincms/templatetags/feincms_thumbnail.py | 10 +- feincms/translations.py | 1 - feincms/urls.py | 12 +- feincms/utils/__init__.py | 3 +- feincms/views/decorators.py | 1 + package.json | 16 + setup.cfg | 63 +- setup.py | 60 +- tests/manage.py | 1 + tests/testapp/applicationcontent_urls.py | 28 +- .../migrate/medialibrary/0001_initial.py | 3 +- tests/testapp/migrate/page/0001_initial.py | 3 +- tests/testapp/migrations/0001_initial.py | 3 +- tests/testapp/models.py | 7 +- tests/testapp/settings.py | 4 +- tests/testapp/tests/__init__.py | 3 +- tests/testapp/tests/test_cms.py | 3 +- tests/testapp/tests/test_extensions.py | 10 +- tests/testapp/tests/test_page.py | 6 +- tests/testapp/tests/test_stuff.py | 5 +- tests/testapp/urls.py | 16 +- tox.ini | 62 +- yarn.lock | 762 +++++++++++ 76 files changed, 2385 insertions(+), 1293 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintrc.js create mode 100644 .github/workflows/tests.yml create mode 100644 .prettierignore create mode 100644 package.json create mode 100644 yarn.lock diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..fd4bd13c7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.py] +indent_size = 4 diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..8e3d952be --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,19 @@ +module.exports = { + env: { + browser: true, + es6: true, + }, + extends: "eslint:recommended", + parserOptions: { + ecmaVersion: 2018, + }, + plugins: ["prettier"], + rules: { + indent: ["error", 2], + "linebreak-style": ["error", "unix"], + semi: ["error", "always"], + "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "prettier/prettier": "error", + quotes: 0, + }, +}; diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..4ef9a6c36 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,50 @@ +name: Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + tests: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - 2.7 + - 3.6 + - 3.7 + - 3.8 + - 3.9 + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip wheel setuptools tox + - name: Run tox targets for ${{ matrix.python-version }} + run: | + ENV_PREFIX=$(tr -C -d "0-9" <<< "${{ matrix.python-version }}") + TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') python -m tox + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install dependencies + run: | + python -m pip install --upgrade pip tox + - name: Run lint + run: tox -e style diff --git a/.gitignore b/.gitignore index 5dd000736..4cdbee3c0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ venv .coverage htmlcov test.zip +node_modules diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..1c0ca47e9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +feincms/static/feincms/jquery-1.11.3.min.js +feincms/static/feincms/jquery-ui-1.10.3.custom.min.js +feincms/static/feincms/js.cookie.js diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b327491c3..4f12ac9b8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,12 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ +- Renamed the main branch to main. +- Switched to a declarative setup. +- Switched to GitHub actions. +- Sorted imports. +- Reformated the JavaScript code using prettier. + `v1.19.0`_ (2021-03-04) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/README.rst b/README.rst index a3fb80618..cf9cf1901 100644 --- a/README.rst +++ b/README.rst @@ -2,10 +2,8 @@ FeinCMS - An extensible Django-based CMS ======================================== -.. image:: https://travis-ci.org/feincms/feincms.svg?branch=next - :target: https://travis-ci.org/feincms/feincms -.. image:: https://travis-ci.org/feincms/feincms.svg?branch=master - :target: https://travis-ci.org/feincms/feincms +.. image:: https://github.com/feincms/feincms/workflows/Tests/badge.svg + :target: https://github.com/feincms/feincms When was the last time, that a pre-built software package you wanted to use got many things right, but in the end, you still needed to modify diff --git a/docs/conf.py b/docs/conf.py index 488cb87be..ff00bfac2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ import os import sys + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -25,20 +26,20 @@ extensions = [] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8' +# source_encoding = 'utf-8' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'FeinCMS' -copyright = u'2009-2010, Feinheit GmbH and contributors' +project = u"FeinCMS" +copyright = u"2009-2010, Feinheit GmbH and contributors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -48,46 +49,47 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) import feincms -version = '.'.join(map(str, feincms.VERSION)) + +version = ".".join(map(str, feincms.VERSION)) # The full version, including alpha/beta/rc tags. release = feincms.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. -#unused_docs = [] +# unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. -exclude_trees = ['_build'] +exclude_trees = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- @@ -95,104 +97,109 @@ # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ['_theme'] -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_use_modindex = True +# html_use_modindex = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' +# html_file_suffix = '' # Output file base name for HTML help builder. -htmlhelp_basename = 'FeinCMSdoc' +htmlhelp_basename = "FeinCMSdoc" # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). -latex_paper_size = 'a4' +latex_paper_size = "a4" # The font size ('10pt', '11pt' or '12pt'). -latex_font_size = '10pt' +latex_font_size = "10pt" # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [( - 'index', 'FeinCMS.tex', u'FeinCMS Documentation', - u'Feinheit GmbH and contributors', 'manual'), +latex_documents = [ + ( + "index", + "FeinCMS.tex", + u"FeinCMS Documentation", + u"Feinheit GmbH and contributors", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # Additional stuff for the LaTeX preamble. -#latex_preamble = '' +# latex_preamble = '' # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_use_modindex = True +# latex_use_modindex = True diff --git a/feincms/__init__.py b/feincms/__init__.py index 392b5aed7..1ec248461 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,14 +1,16 @@ from __future__ import absolute_import, unicode_literals + VERSION = (1, 19, 0) __version__ = ".".join(map(str, VERSION)) class LazySettings(object): def _load_settings(self): - from feincms import default_settings from django.conf import settings as django_settings + from feincms import default_settings + for key in dir(default_settings): if not key.startswith("FEINCMS_"): continue @@ -59,9 +61,10 @@ def ensure_completely_loaded(force=False): # Here we flush the caches rather than actually _filling them so # that relations defined after all content types registrations # don't miss out. - import django from distutils.version import LooseVersion + import django + if LooseVersion(django.get_version()) < LooseVersion("1.8"): for model in apps.get_models(): diff --git a/feincms/_internal.py b/feincms/_internal.py index 44a669748..f0034dfee 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -7,6 +7,7 @@ from __future__ import absolute_import, unicode_literals from distutils.version import LooseVersion + from django import get_version from django.template.loader import render_to_string diff --git a/feincms/admin/__init__.py b/feincms/admin/__init__.py index 9008a9982..9bd00dfcb 100644 --- a/feincms/admin/__init__.py +++ b/feincms/admin/__init__.py @@ -1,7 +1,8 @@ from __future__ import absolute_import from django.contrib.admin.filters import FieldListFilter -from .filters import ParentFieldListFilter, CategoryFieldListFilter + +from .filters import CategoryFieldListFilter, ParentFieldListFilter FieldListFilter.register( diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index 2d8bcbf0c..bb269dd05 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -6,12 +6,12 @@ from __future__ import absolute_import, unicode_literals +from django import VERSION as DJANGO_VERSION from django.contrib.admin.filters import ChoicesFieldListFilter from django.db.models import Count from django.utils.encoding import smart_text from django.utils.safestring import mark_safe from django.utils.translation import gettext as _ -from django import VERSION as DJANGO_VERSION from feincms.utils import shorten_string diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 6c22aa627..01ba0f2c6 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -4,12 +4,12 @@ from __future__ import absolute_import, unicode_literals -from functools import reduce import json import logging +from functools import reduce -from django.contrib.admin.views import main from django.contrib.admin.actions import delete_selected +from django.contrib.admin.views import main from django.contrib.auth import get_permission_codename from django.db.models import Q from django.http import ( @@ -19,17 +19,17 @@ HttpResponseNotFound, HttpResponseServerError, ) +from django.utils.encoding import force_text from django.utils.html import escape from django.utils.safestring import mark_safe -from django.utils.translation import gettext_lazy as _, gettext -from django.utils.encoding import force_text - +from django.utils.translation import gettext, gettext_lazy as _ from mptt.exceptions import InvalidMove from mptt.forms import MPTTAdminForm from feincms import settings from feincms.extensions import ExtensionModelAdmin + try: # Django<3 from django.contrib.staticfiles.templatetags.staticfiles import static diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 9a5568b55..6eb4735db 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -1,10 +1,10 @@ from __future__ import absolute_import +import warnings from collections import OrderedDict from email.utils import parsedate from functools import partial, wraps from time import mktime -import warnings from django.conf import settings from django.core.cache import cache @@ -16,14 +16,15 @@ from django.utils.safestring import mark_safe from django.utils.translation import get_language, gettext_lazy as _ + try: from django.urls import ( NoReverseMatch, - reverse, - get_script_prefix, - set_script_prefix, Resolver404, + get_script_prefix, resolve, + reverse, + set_script_prefix, ) except ImportError: from django.core.urlresolvers import ( diff --git a/feincms/content/contactform/__init__.py b/feincms/content/contactform/__init__.py index c25396137..5d3fb54d8 100644 --- a/feincms/content/contactform/__init__.py +++ b/feincms/content/contactform/__init__.py @@ -3,6 +3,7 @@ import warnings + warnings.warn( "The contactform content has been deprecated. Use form-designer instead.", DeprecationWarning, diff --git a/feincms/content/filer/models.py b/feincms/content/filer/models.py index 2feba4578..5213ead70 100644 --- a/feincms/content/filer/models.py +++ b/feincms/content/filer/models.py @@ -5,8 +5,9 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from feincms.admin.item_editor import FeinCMSInline from feincms._internal import ct_render_to_string +from feincms.admin.item_editor import FeinCMSInline + try: from filer.fields.file import FilerFileField diff --git a/feincms/content/medialibrary/models.py b/feincms/content/medialibrary/models.py index bc7d2f474..0e0a10ed3 100644 --- a/feincms/content/medialibrary/models.py +++ b/feincms/content/medialibrary/models.py @@ -5,6 +5,7 @@ from feincms.module.medialibrary.contents import MediaFileContent + warnings.warn( "Import MediaFileContent from feincms.module.medialibrary.contents.", DeprecationWarning, diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index 6d359e5dd..4a03fe972 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -2,13 +2,12 @@ import json import logging -import six from distutils.version import LooseVersion -from django import get_version -from django import forms -from django.db import models +import six +from django import forms, get_version from django.core.serializers.json import DjangoJSONEncoder +from django.db import models class JSONFormField(forms.fields.CharField): diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index f5652ea03..2b496a678 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -11,16 +11,15 @@ from __future__ import absolute_import, unicode_literals import six - -from django import forms, VERSION +from django import VERSION, forms from django.contrib.admin.widgets import FilteredSelectMultiple from django.db.models.signals import pre_save from django.utils.translation import gettext_lazy as _ - from tagging.fields import TagField from tagging.models import Tag from tagging.utils import parse_tag_input + try: from tagging.registry import AlreadyRegistered except ImportError: diff --git a/feincms/default_settings.py b/feincms/default_settings.py index a0d20be5c..93cbc88be 100644 --- a/feincms/default_settings.py +++ b/feincms/default_settings.py @@ -12,6 +12,7 @@ from django.conf import settings + # e.g. 'uploads' if you would prefer /uploads/imagecontent/test.jpg # to /imagecontent/test.jpg. FEINCMS_UPLOAD_PREFIX = getattr(settings, "FEINCMS_UPLOAD_PREFIX", "") diff --git a/feincms/extensions/__init__.py b/feincms/extensions/__init__.py index ad37b177f..74a10a8a6 100644 --- a/feincms/extensions/__init__.py +++ b/feincms/extensions/__init__.py @@ -1,12 +1,13 @@ from __future__ import absolute_import from .base import ( - ExtensionsMixin, Extension, ExtensionModelAdmin, + ExtensionsMixin, prefetch_modeladmin_get_queryset, ) + __all__ = ( "ExtensionsMixin", "Extension", diff --git a/feincms/extensions/base.py b/feincms/extensions/base.py index e2701090a..375bf045b 100644 --- a/feincms/extensions/base.py +++ b/feincms/extensions/base.py @@ -4,10 +4,10 @@ from __future__ import absolute_import, unicode_literals -from functools import wraps -import six import inspect +from functools import wraps +import six from django.contrib import admin from django.core.exceptions import ImproperlyConfigured diff --git a/feincms/extensions/changedate.py b/feincms/extensions/changedate.py index 880641fba..cf07cbb58 100644 --- a/feincms/extensions/changedate.py +++ b/feincms/extensions/changedate.py @@ -7,7 +7,7 @@ from __future__ import absolute_import, unicode_literals -from email.utils import parsedate_tz, mktime_tz +from email.utils import mktime_tz, parsedate_tz from time import mktime from django.db import models diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index 695d09585..14f5dda93 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -11,7 +11,6 @@ from __future__ import absolute_import, unicode_literals from datetime import datetime -from pytz.exceptions import AmbiguousTimeError from django.db import models from django.db.models import Q @@ -19,6 +18,7 @@ from django.utils.cache import patch_response_headers from django.utils.html import mark_safe from django.utils.translation import gettext_lazy as _ +from pytz.exceptions import AmbiguousTimeError from feincms import extensions diff --git a/feincms/extensions/translations.py b/feincms/extensions/translations.py index 3893808a2..662065017 100644 --- a/feincms/extensions/translations.py +++ b/feincms/extensions/translations.py @@ -28,8 +28,8 @@ from django.utils.translation import gettext_lazy as _ from feincms import extensions, settings -from feincms.translations import is_primary_language from feincms._internal import monkeypatch_method, monkeypatch_property +from feincms.translations import is_primary_language # ------------------------------------------------------------------------ diff --git a/feincms/management/commands/medialibrary_to_filer.py b/feincms/management/commands/medialibrary_to_filer.py index 2ac3fefec..cf1f08688 100644 --- a/feincms/management/commands/medialibrary_to_filer.py +++ b/feincms/management/commands/medialibrary_to_filer.py @@ -1,16 +1,15 @@ from __future__ import absolute_import, unicode_literals +from django.contrib.auth.models import User from django.core.files import File as DjangoFile from django.core.management.base import NoArgsCommand -from django.contrib.auth.models import User +from filer.models import File, Image from feincms.contents import FilerFileContent, FilerImageContent from feincms.module.medialibrary.contents import MediaFileContent from feincms.module.medialibrary.models import MediaFile from feincms.module.page.models import Page -from filer.models import File, Image - PageMediaFileContent = Page.content_type_for(MediaFileContent) PageFilerFileContent = Page.content_type_for(FilerFileContent) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index f290daa50..6a77ab3c1 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -10,6 +10,7 @@ from __future__ import absolute_import, unicode_literals + try: from django.core.management.base import NoArgsCommand as BaseCommand except ImportError: diff --git a/feincms/models.py b/feincms/models.py index 461c31df1..5b93fd4e6 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -7,13 +7,13 @@ from __future__ import absolute_import, unicode_literals -from collections import OrderedDict -from functools import reduce -import six -import sys import operator +import sys import warnings +from collections import OrderedDict +from functools import reduce +import six from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured from django.db import connections, models diff --git a/feincms/module/extensions/changedate.py b/feincms/module/extensions/changedate.py index fdfd93475..865cdb062 100644 --- a/feincms/module/extensions/changedate.py +++ b/feincms/module/extensions/changedate.py @@ -5,6 +5,7 @@ from feincms.extensions.changedate import * + warnings.warn( "Import %(name)s from feincms.extensions.%(name)s" % {"name": __name__.split(".")[-1]}, diff --git a/feincms/module/extensions/ct_tracker.py b/feincms/module/extensions/ct_tracker.py index f810b346e..6ea11bd32 100644 --- a/feincms/module/extensions/ct_tracker.py +++ b/feincms/module/extensions/ct_tracker.py @@ -5,6 +5,7 @@ from feincms.extensions.ct_tracker import * + warnings.warn( "Import %(name)s from feincms.extensions.%(name)s" % {"name": __name__.split(".")[-1]}, diff --git a/feincms/module/extensions/datepublisher.py b/feincms/module/extensions/datepublisher.py index 313568d74..b95b01633 100644 --- a/feincms/module/extensions/datepublisher.py +++ b/feincms/module/extensions/datepublisher.py @@ -5,6 +5,7 @@ from feincms.extensions.datepublisher import * + warnings.warn( "Import %(name)s from feincms.extensions.%(name)s" % {"name": __name__.split(".")[-1]}, diff --git a/feincms/module/extensions/featured.py b/feincms/module/extensions/featured.py index 7713d026b..5b947c84f 100644 --- a/feincms/module/extensions/featured.py +++ b/feincms/module/extensions/featured.py @@ -5,6 +5,7 @@ from feincms.extensions.featured import * + warnings.warn( "Import %(name)s from feincms.extensions.%(name)s" % {"name": __name__.split(".")[-1]}, diff --git a/feincms/module/extensions/seo.py b/feincms/module/extensions/seo.py index aa386950f..d81fe2b69 100644 --- a/feincms/module/extensions/seo.py +++ b/feincms/module/extensions/seo.py @@ -5,6 +5,7 @@ from feincms.extensions.seo import * + warnings.warn( "Import %(name)s from feincms.extensions.%(name)s" % {"name": __name__.split(".")[-1]}, diff --git a/feincms/module/extensions/translations.py b/feincms/module/extensions/translations.py index c89c8d538..68e27512a 100644 --- a/feincms/module/extensions/translations.py +++ b/feincms/module/extensions/translations.py @@ -5,6 +5,7 @@ from feincms.extensions.translations import * + warnings.warn( "Import %(name)s from feincms.extensions.%(name)s" % {"name": __name__.split(".")[-1]}, diff --git a/feincms/module/medialibrary/__init__.py b/feincms/module/medialibrary/__init__.py index 98a59597d..b2d495235 100644 --- a/feincms/module/medialibrary/__init__.py +++ b/feincms/module/medialibrary/__init__.py @@ -6,6 +6,7 @@ import logging + # ------------------------------------------------------------------------ logger = logging.getLogger("feincms.medialibrary") diff --git a/feincms/module/medialibrary/admin.py b/feincms/module/medialibrary/admin.py index 922450af9..91103eb38 100644 --- a/feincms/module/medialibrary/admin.py +++ b/feincms/module/medialibrary/admin.py @@ -6,8 +6,9 @@ from django.contrib import admin -from .models import Category, MediaFile from .modeladmins import CategoryAdmin, MediaFileAdmin +from .models import Category, MediaFile + # ------------------------------------------------------------------------ admin.site.register(Category, CategoryAdmin) diff --git a/feincms/module/medialibrary/fields.py b/feincms/module/medialibrary/fields.py index 9682bd6b9..3d7417efa 100644 --- a/feincms/module/medialibrary/fields.py +++ b/feincms/module/medialibrary/fields.py @@ -5,9 +5,7 @@ from __future__ import absolute_import, unicode_literals import six - -from django.contrib.admin.widgets import AdminFileWidget -from django.contrib.admin.widgets import ForeignKeyRawIdWidget +from django.contrib.admin.widgets import AdminFileWidget, ForeignKeyRawIdWidget from django.db import models from django.utils.html import escape from django.utils.safestring import mark_safe @@ -15,6 +13,7 @@ from feincms.admin.item_editor import FeinCMSInline from feincms.utils import shorten_string + from .models import MediaFile from .thumbnail import admin_thumbnail diff --git a/feincms/module/medialibrary/forms.py b/feincms/module/medialibrary/forms.py index 38df3ab8f..e48f73539 100644 --- a/feincms/module/medialibrary/forms.py +++ b/feincms/module/medialibrary/forms.py @@ -12,8 +12,8 @@ from feincms import settings from . import logger -from .models import Category, MediaFile from .fields import AdminFileWithPreviewWidget +from .models import Category, MediaFile # ------------------------------------------------------------------------ diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index adc217430..7cc72e36c 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -8,8 +8,7 @@ from django import forms from django.conf import settings as django_settings -from django.contrib import admin -from django.contrib import messages +from django.contrib import admin, messages from django.contrib.auth.decorators import permission_required from django.contrib.sites.shortcuts import get_current_site from django.core.files.images import get_image_dimensions @@ -17,9 +16,10 @@ from django.shortcuts import render from django.template.defaultfilters import filesizeformat from django.utils.safestring import mark_safe -from django.utils.translation import ungettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _, ungettext from django.views.decorators.csrf import csrf_protect + try: from django.urls import reverse except ImportError: @@ -29,8 +29,8 @@ from feincms.translations import admin_translationinline, lookup_translations from feincms.utils import shorten_string -from .models import Category, MediaFileTranslation from .forms import MediaCategoryAdminForm, MediaFileAdminForm +from .models import Category, MediaFileTranslation from .thumbnail import admin_thumbnail from .zip import import_zipfile diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 738beef14..beca82997 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -6,9 +6,9 @@ import os import re -import six import django +import six from django.db import models from django.db.models.signals import post_delete from django.dispatch.dispatcher import receiver @@ -19,9 +19,9 @@ from feincms import settings from feincms.models import ExtensionsMixin from feincms.translations import ( + TranslatedObjectManager, TranslatedObjectMixin, Translation, - TranslatedObjectManager, ) from . import logger diff --git a/feincms/module/medialibrary/zip.py b/feincms/module/medialibrary/zip.py index 2e91376f6..3f16b7641 100644 --- a/feincms/module/medialibrary/zip.py +++ b/feincms/module/medialibrary/zip.py @@ -10,9 +10,9 @@ from __future__ import absolute_import, unicode_literals import json -import zipfile import os import time +import zipfile from django.conf import settings as django_settings from django.core.files.base import ContentFile diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index e4c61602e..8a396aa88 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -8,8 +8,10 @@ from django.core.exceptions import ImproperlyConfigured from feincms import ensure_completely_loaded, settings -from .models import Page + from .modeladmins import PageAdmin +from .models import Page + try: from django.core.exceptions import FieldDoesNotExist diff --git a/feincms/module/page/extensions/navigation.py b/feincms/module/page/extensions/navigation.py index 9f03311a0..85bab288e 100644 --- a/feincms/module/page/extensions/navigation.py +++ b/feincms/module/page/extensions/navigation.py @@ -9,17 +9,17 @@ from __future__ import absolute_import, unicode_literals -from collections import OrderedDict -import six import types +from collections import OrderedDict +import six from django.db import models from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from feincms import extensions -from feincms.utils import get_object, shorten_string from feincms._internal import monkeypatch_method +from feincms.utils import get_object, shorten_string class TypeRegistryMetaClass(type): diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 114a97378..c86c4841b 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -11,11 +11,10 @@ from django.forms.models import model_to_dict from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ +from mptt.forms import MPTTAdminForm from feincms import ensure_completely_loaded -from mptt.forms import MPTTAdminForm - class RedirectToWidget(ForeignKeyRawIdWidget): def label_for_value(self, value): diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 5f0b94fbe..070c2a735 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -8,13 +8,13 @@ from threading import local from django.conf import settings as django_settings -from django.core.exceptions import PermissionDenied +from django.contrib import admin, messages from django.contrib.contenttypes.models import ContentType -from django.contrib import admin -from django.contrib import messages +from django.core.exceptions import PermissionDenied from django.http import HttpResponseRedirect from django.utils.translation import gettext_lazy as _ + try: from django.urls import reverse except ImportError: @@ -26,8 +26,7 @@ # Newer Django versions. from django.templatetags.static import static -from feincms import ensure_completely_loaded -from feincms import settings +from feincms import ensure_completely_loaded, settings from feincms.admin import item_editor, tree_editor # ------------------------------------------------------------------------ diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index 281d7364b..e642ce7f2 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -5,13 +5,13 @@ from __future__ import absolute_import, unicode_literals import six - from django.core.exceptions import PermissionDenied from django.db import models from django.db.models import Q from django.http import Http404 from django.utils.translation import gettext_lazy as _ + try: from django.urls import reverse except ImportError: @@ -23,8 +23,8 @@ from feincms.models import create_base_model from feincms.module.mixins import ContentModelMixin from feincms.module.page import processors +from feincms.utils import get_model_instance, match_model_string, shorten_string from feincms.utils.managers import ActiveAwareContentManagerMixin -from feincms.utils import shorten_string, match_model_string, get_model_instance # ------------------------------------------------------------------------ diff --git a/feincms/module/page/sitemap.py b/feincms/module/page/sitemap.py index c5cbd5850..46667b7b5 100644 --- a/feincms/module/page/sitemap.py +++ b/feincms/module/page/sitemap.py @@ -5,8 +5,8 @@ from __future__ import absolute_import, unicode_literals from django.apps import apps -from django.db.models import Max from django.contrib.sitemaps import Sitemap +from django.db.models import Max from feincms import settings diff --git a/feincms/signals.py b/feincms/signals.py index 2d4fca135..0655b3ec4 100644 --- a/feincms/signals.py +++ b/feincms/signals.py @@ -11,6 +11,7 @@ from django.dispatch import Signal + # ------------------------------------------------------------------------ # This signal is sent when an item editor managed object is completely # saved, especially including all foreign or manytomany dependencies. diff --git a/feincms/static/feincms/item_editor.css b/feincms/static/feincms/item_editor.css index 69ba18640..3f80d1539 100644 --- a/feincms/static/feincms/item_editor.css +++ b/feincms/static/feincms/item_editor.css @@ -1,278 +1,312 @@ .navi_tab { - float:left; - padding: 8px 10px; - cursor:pointer; - margin-top:3px; - font-weight: bold; - font-size: 11px; - color: #666; - background: #f6f6f6; - border: 1px solid #eee; - text-transform: uppercase; + float: left; + padding: 8px 10px; + cursor: pointer; + margin-top: 3px; + font-weight: bold; + font-size: 11px; + color: #666; + background: #f6f6f6; + border: 1px solid #eee; + text-transform: uppercase; } .tab_active { - background: #79aec8; - color: white; - border-color: #79aec8; + background: #79aec8; + color: white; + border-color: #79aec8; } #feincmsmain { - clear:both; - padding: 10px 10px 10px 10px; - border: 1px solid #eee; - margin: 0 0 10px 0; + clear: both; + padding: 10px 10px 10px 10px; + border: 1px solid #eee; + margin: 0 0 10px 0; } .panel { - display:none; - position:relative; - padding-bottom: 39px; + display: none; + position: relative; + padding-bottom: 39px; } .order-item { - margin: 0 0 10px 0; - position:relative; - + margin: 0 0 10px 0; + position: relative; } .order-item h2 { - background-image: url('img/arrow-move.png'); - background-repeat: no-repeat; - background-position: 6px 9px; + background-image: url("img/arrow-move.png"); + background-repeat: no-repeat; + background-position: 6px 9px; } .order-item .handle { - display: inline-block; - height: 14px; - width: 15px; - cursor: move; + display: inline-block; + height: 14px; + width: 15px; + cursor: move; } .order-item .collapse { - cursor: pointer; - /*color: #444;*/ - font-weight: normal; + cursor: pointer; + /*color: #444;*/ + font-weight: normal; - border-bottom: 1px solid rgba(255, 255, 255, 0.25); + border-bottom: 1px solid rgba(255, 255, 255, 0.25); } .order-item .collapse:hover { - opacity: 0.7; + opacity: 0.7; } .item-delete { - cursor:pointer; - float:right; - margin: 4px 3px 0px 0; + cursor: pointer; + float: right; + margin: 4px 3px 0px 0; } -.highlight, .helper { - height: 34px; - margin: 0 0 10px 0; - border: none; - opacity: 0.3; - background: #79aec8; +.highlight, +.helper { + height: 34px; + margin: 0 0 10px 0; + border: none; + opacity: 0.3; + background: #79aec8; } -.helper{ - height: 25px !important; - opacity: 1; +.helper { + height: 25px !important; + opacity: 1; } .button { - margin:5px; padding:5px; - font-weight: bold; - cursor:pointer; - border: 1px solid #678; + margin: 5px; + padding: 5px; + font-weight: bold; + cursor: pointer; + border: 1px solid #678; } select { - max-width: 580px; + max-width: 580px; } #feincmsmain_wrapper { - margin: 10px 0 30px 0; + margin: 10px 0 30px 0; } -.clearfix { *zoom:1; } -.clearfix:before, .clearfix:after { content: " "; display: table; } -.clearfix:after { clear: both; } +.clearfix { + *zoom: 1; +} +.clearfix:before, +.clearfix:after { + content: " "; + display: table; +} +.clearfix:after { + clear: both; +} textarea { - width: 580px; - margin-top:5px; - margin-bottom:5px; + width: 580px; + margin-top: 5px; + margin-bottom: 5px; } .inline-group .tabular textarea { - width: auto; + width: auto; } .item-controls { - position: absolute; - top: 2px; - right: 32px; + position: absolute; + top: 2px; + right: 32px; } .item-control-unit { - float:left; + float: left; } .item-controls select { - margin-left: 7px; + margin-left: 7px; } .machine-control { - padding: 5px 10px 5px 10px; - border: 1px solid #ccc; - background-color: #edf3fe; - position:absolute; - left:-11px; - bottom:-30px; - width: 100%; + padding: 5px 10px 5px 10px; + border: 1px solid #ccc; + background-color: #edf3fe; + position: absolute; + left: -11px; + bottom: -30px; + width: 100%; - background: #f8f8f8; - border: 1px solid #eee; - height: 55px; + background: #f8f8f8; + border: 1px solid #eee; + height: 55px; } .machine-control .button { - padding-top: 6px; - padding-bottom: 6px; + padding-top: 6px; + padding-bottom: 6px; } .control-unit { - float:left; - padding: 0 20px 0 5px; - border-left: 1px solid #eee; + float: left; + padding: 0 20px 0 5px; + border-left: 1px solid #eee; } .control-unit:first-child { - border-left: none; + border-left: none; } .control-unit span { - font-weight:bold; + font-weight: bold; } a.actionbutton { - display: block; - background-repeat: no-repeat; - width:50px; - height:50px; - float:left; - margin: 5px 0 0 20px; - text-indent:-7000px; + display: block; + background-repeat: no-repeat; + width: 50px; + height: 50px; + float: left; + margin: 5px 0 0 20px; + text-indent: -7000px; } -a.richtextcontent { background: url(img/contenttypes.png) no-repeat 0 0; } -a.richtextcontent:hover { background-position: 0 -70px; } +a.richtextcontent { + background: url(img/contenttypes.png) no-repeat 0 0; +} +a.richtextcontent:hover { + background-position: 0 -70px; +} -a.imagecontent { background: url(img/contenttypes.png) no-repeat -70px 0; } -a.imagecontent:hover { background-position: -70px -70px; } +a.imagecontent { + background: url(img/contenttypes.png) no-repeat -70px 0; +} +a.imagecontent:hover { + background-position: -70px -70px; +} -a.gallerycontent { background: url(img/contenttypes.png) no-repeat -140px 0; } -a.gallerycontent:hover { background-position: -140px -70px; } +a.gallerycontent { + background: url(img/contenttypes.png) no-repeat -140px 0; +} +a.gallerycontent:hover { + background-position: -140px -70px; +} -a.oembedcontent { background: url(img/contenttypes.png) no-repeat -280px 0; } -a.oembedcontent:hover { background-position: -280px -70px; } +a.oembedcontent { + background: url(img/contenttypes.png) no-repeat -280px 0; +} +a.oembedcontent:hover { + background-position: -280px -70px; +} -a.pdfcontent { background: url(img/contenttypes.png) no-repeat -210px 0; } -a.pdfcontent:hover { background-position: -210px -70px; } +a.pdfcontent { + background: url(img/contenttypes.png) no-repeat -210px 0; +} +a.pdfcontent:hover { + background-position: -210px -70px; +} -a.audiocontent { background: url(img/contenttypes.png) no-repeat -350px 0; } -a.audiocontent:hover { background-position: -350px -70px; } +a.audiocontent { + background: url(img/contenttypes.png) no-repeat -350px 0; +} +a.audiocontent:hover { + background-position: -350px -70px; +} .control-unit select { - float: left; - position: relative; - top: 13px; + float: left; + position: relative; + top: 13px; } .empty-machine-msg { - margin:10px 0px 20px 20px; - font-size:14px; + margin: 10px 0px 20px 20px; + font-size: 14px; } td span select { - width:600px; + width: 600px; } - .change-template-button { - margin-left: 7em; - padding-left: 30px; + margin-left: 7em; + padding-left: 30px; } /* Allow nested lists in error items */ ul.errorlist ul { - margin-left: 1em; - padding-left: 0; - list-style-type: square; + margin-left: 1em; + padding-left: 0; + list-style-type: square; } ul.errorlist li li { - /* Avoid repeating the warning image every time*/ - background-image:none; - padding: 0; + /* Avoid repeating the warning image every time*/ + background-image: none; + padding: 0; } -div.order-machine div.inline-related > h3{ - display: none; +div.order-machine div.inline-related > h3 { + display: none; } .hidden-form-row { - display: none; + display: none; } #extension_options_wrapper { border-bottom: 1px solid #eee; } -#extension_options>.module.aligned { +#extension_options > .module.aligned { border-top: 1px solid #eee; margin-bottom: -1px; } - /* various overrides */ -#id_redirect_to { width: 20em; } /* raw_id_fields act-a-like for redirect_to */ +#id_redirect_to { + width: 20em; +} /* raw_id_fields act-a-like for redirect_to */ /* overwrite flat theme default label width because of problems with the CKEditor */ -.aligned .text label { width: auto; } - +.aligned .text label { + width: auto; +} /* django suit hacks */ /*********************/ #suit-center #feincmsmain { - clear:none; + clear: none; } #suit-center .panel { - padding-top: 15px; + padding-top: 15px; } #suit-center .form-horizontal .inline-related fieldset { - margin-top: 10px; + margin-top: 10px; } #suit-center .panel h2 { - color: white; - font-size: 13px; - line-height: 12px; - margin-left: 0; - text-shadow: none; + color: white; + font-size: 13px; + line-height: 12px; + margin-left: 0; + text-shadow: none; } #suit-center .item-delete { - margin: 3px 5px 0 0; + margin: 3px 5px 0 0; } #suit-center .order-item .handle { - height: 36px; + height: 36px; } #suit-center .order-machine .order-item { - margin-top: 10px; + margin-top: 10px; } diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index 2a2c4de7f..a64f9a57f 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -1,603 +1,687 @@ +/* global Downcoder, django, feincms */ +/* global IMG_DELETELINK_PATH, REGION_MAP, REGION_NAMES, ACTIVE_REGION, CONTENT_NAMES, FEINCMS_ITEM_EDITOR_GETTEXT, CONTENT_TYPE_BUTTONS */ +/* global contentblock_init_handlers, contentblock_move_handlers */ +/* global id_to_windowname */ +/* global template_regions */ + // IE<9 lacks Array.prototype.indexOf if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function(needle) { - for (i=0, l=this.length; i").addClass("module aligned order-item item-wrapper-" + modvar); - var original_id_id = '#id_' + form.attr('id') + '-id'; - - var wrp = ['

    ']; - // If original has delete checkbox or this is a freshly added CT? Add delete link! - if($('.delete', form).length || !$(original_id_id, form).val()) { - wrp.push(''); - } - wrp.push(' '+modname+'

    '); - wrp.push('
    '); - fieldset.append(wrp.join("")); - - fieldset.children(".item-content").append(form); //relocates, not clone - - $("
    ").addClass("item-controls").appendTo(fieldset); - - return fieldset; - } - - - SELECTS = {}; - function save_content_type_selects() { - $('#feincmsmain>.panel').each(function() { - SELECTS[this.id.replace(/_body$/, '')] = $("select[name=order-machine-add-select]", this).clone().removeAttr("name"); - }); +(function ($) { + // Patch up urlify maps to generate nicer slugs in german + if (typeof Downcoder != "undefined") { + Downcoder.Initialize(); + Downcoder.map["ö"] = Downcoder.map["Ö"] = "oe"; + Downcoder.map["ä"] = Downcoder.map["Ä"] = "ae"; + Downcoder.map["ü"] = Downcoder.map["Ü"] = "ue"; + } + + function feincms_gettext(s) { + // Unfortunately, we cannot use Django's jsi18n view for this + // because it only sends translations from the package + // "django.conf" -- our own djangojs domain strings won't be + // picked up + + if (FEINCMS_ITEM_EDITOR_GETTEXT[s]) return FEINCMS_ITEM_EDITOR_GETTEXT[s]; + return s; + } + + function create_new_item_from_form(form, modname, modvar) { + let fieldset = $("
    ").addClass( + "module aligned order-item item-wrapper-" + modvar + ); + let original_id_id = "#id_" + form.attr("id") + "-id"; + + let wrp = ["

    "]; + // If original has delete checkbox or this is a freshly added CT? Add delete link! + if ($(".delete", form).length || !$(original_id_id, form).val()) { + wrp.push(''); } - - function update_item_controls(item, target_region_id){ - var item_controls = item.find(".item-controls"); - item_controls.empty(); - - // Insert control unit - var insert_control = $("
    ").addClass("item-control-unit"); - var select_content = SELECTS[REGION_MAP[target_region_id]].clone(); - - select_content.change(function() { - var modvar = select_content.val(); - var modname = select_content.find("option:selected").html(); - var new_fieldset = create_new_fieldset_from_module(modvar, modname); - add_fieldset(target_region_id, new_fieldset, {where:'insertBefore', relative_to:item, animate:true}); - update_item_controls(new_fieldset, target_region_id); - - select_content.val(''); - }); - insert_control.append(select_content); - item_controls.append(insert_control); - - // Move control unit - if (REGION_MAP.length > 1) { - var wrp = []; - wrp.push('
    '); - - var move_control = $(wrp.join("")); - move_control.find("select").change(function(){ - var move_to = $(this).val(); - move_item(REGION_MAP.indexOf(move_to), item); - }); - item_controls.append(move_control); // Add new one + wrp.push( + ' ' + + modname + + "

    " + ); + wrp.push('
    '); + fieldset.append(wrp.join("")); + + fieldset.children(".item-content").append(form); //relocates, not clone + + $("
    ").addClass("item-controls").appendTo(fieldset); + + return fieldset; + } + + const SELECTS = {}; + function save_content_type_selects() { + $("#feincmsmain>.panel").each(function () { + SELECTS[this.id.replace(/_body$/, "")] = $( + "select[name=order-machine-add-select]", + this + ) + .clone() + .removeAttr("name"); + }); + } + + function update_item_controls(item, target_region_id) { + let item_controls = item.find(".item-controls"); + item_controls.empty(); + + // Insert control unit + let insert_control = $("
    ").addClass("item-control-unit"); + let select_content = SELECTS[REGION_MAP[target_region_id]].clone(); + + select_content.change(function () { + let modvar = select_content.val(); + let modname = select_content.find("option:selected").html(); + let new_fieldset = create_new_fieldset_from_module(modvar, modname); + add_fieldset(target_region_id, new_fieldset, { + where: "insertBefore", + relative_to: item, + animate: true, + }); + update_item_controls(new_fieldset, target_region_id); + + select_content.val(""); + }); + insert_control.append(select_content); + item_controls.append(insert_control); + + // Move control unit + if (REGION_MAP.length > 1) { + let wrp = []; + wrp.push( + '
    "); + + let move_control = $(wrp.join("")); + move_control.find("select").change(function () { + let move_to = $(this).val(); + move_item(REGION_MAP.indexOf(move_to), item); + }); + item_controls.append(move_control); // Add new one } + } + function create_new_fieldset_from_module(modvar, modname) { + let new_form = create_new_spare_form(modvar); + return create_new_item_from_form(new_form, modname, modvar); + } - function create_new_fieldset_from_module(modvar, modname) { - var new_form = create_new_spare_form(modvar); - return create_new_item_from_form(new_form, modname, modvar); - } - - function add_fieldset(region_id, item, how){ - /* `how` should be an object. + function add_fieldset(region_id, item, how) { + /* `how` should be an object. `how.where` should be one of: - 'append' -- last region - 'prepend' -- first region - 'insertBefore' -- insert before relative_to - 'insertAfter' -- insert after relative_to */ - // Default parameters - if (how) $.extend({ - where: 'append', - relative_to: undefined, - animate: false - }, how); - - item.hide(); - if(how.where == 'append' || how.where == 'prepend'){ - $("#"+ REGION_MAP[region_id] +"_body").children("div.order-machine")[how.where](item); - } - else if(how.where == 'insertBefore' || how.where == 'insertAfter'){ - if(how.relative_to){ - item[how.where](how.relative_to); - } - else{ - window.alert('DEBUG: invalid add_fieldset usage'); - return; - } - } - else{ - window.alert('DEBUG: invalid add_fieldset usage'); - return; - } - set_item_field_value(item, "region-choice-field", region_id); - init_contentblocks(); - - if (how.animate) { - item.fadeIn(800); - } - else { - item.show(); - } - } - - function create_new_spare_form(modvar) { - var old_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val(), 10); - // **** UGLY CODE WARNING, avert your gaze! **** - // for some unknown reason, the add-button click handler function - // fails on the first triggerHandler call in some rare cases; - // we can detect this here and retry: - for(var i = 0; i < 2; i++){ - // Use Django's built-in inline spawing mechanism (Django 1.2+) - // must use django.jQuery since the bound function lives there: - django.jQuery('#'+modvar+'_set-group').find( - '.add-row a').triggerHandler('click'); - var new_form_count = parseInt($('#id_'+modvar+'_set-TOTAL_FORMS').val(), 10); - if(new_form_count > old_form_count){ - return $('#'+modvar+'_set-'+(new_form_count-1)); - } - } - } - - function set_item_field_value(item, field, value) { - // item: DOM object for the item's fieldset. - // field: "order-field" | "delete-field" | "region-choice-field" - if (field=="delete-field") - item.find("."+field).attr("checked",value); - else if (field=="region-choice-field") { - var old_region_id = REGION_MAP.indexOf(item.find("."+field).val()); - item.find("."+field).val(REGION_MAP[value]); - - // show/hide the empty machine message in the source and - // target region. - old_region_item = $("#"+REGION_MAP[old_region_id]+"_body"); - if (old_region_item.children("div.order-machine").children().length == 0) - old_region_item.children("div.empty-machine-msg").show(); - else - old_region_item.children("div.empty-machine-msg").hide(); - - new_region_item = $("#"+REGION_MAP[value]+"_body"); - new_region_item.children("div.empty-machine-msg").hide(); - } - else - item.find("."+field).val(value); - } - - function move_item(region_id, item) { - poorify_rich(item); - item.fadeOut(800, function() { - add_fieldset(region_id, item, {where:'append'}); - richify_poor(item); - update_item_controls(item, region_id); - item.show(); - }); - } - - function poorify_rich(item){ - item.children(".item-content").hide(); - - for (var i=0; i v2 ? 1 : -1; + } + + function create_new_spare_form(modvar) { + let old_form_count = parseInt( + $("#id_" + modvar + "_set-TOTAL_FORMS").val(), + 10 + ); + // **** UGLY CODE WARNING, avert your gaze! **** + // for some unknown reason, the add-button click handler function + // fails on the first triggerHandler call in some rare cases; + // we can detect this here and retry: + for (let i = 0; i < 2; i++) { + // Use Django's built-in inline spawing mechanism (Django 1.2+) + // must use django.jQuery since the bound function lives there: + django + .jQuery("#" + modvar + "_set-group") + .find(".add-row a") + .triggerHandler("click"); + let new_form_count = parseInt( + $("#id_" + modvar + "_set-TOTAL_FORMS").val(), + 10 + ); + if (new_form_count > old_form_count) { + return $("#" + modvar + "_set-" + (new_form_count - 1)); + } } - - function give_ordering_to_content_types() { - for (var i=0; i v2 ? 1 : -1; + } + + function give_ordering_to_content_types() { + for (let i = 0; i < REGION_MAP.length; i++) { + let container = $("#" + REGION_MAP[i] + "_body div.order-machine"); + for (let j = 0; j < container.children().length; j++) { + set_item_field_value( + container.find("fieldset.order-item:eq(" + j + ")"), + "order-field", + j + ); } } - - function order_content_types_in_regions() { - for (var i=0; i
\ No newline at end of file + diff --git a/feincms/templates/breadcrumbs.html b/feincms/templates/breadcrumbs.html index 52fd8c6af..5322eb37c 100644 --- a/feincms/templates/breadcrumbs.html +++ b/feincms/templates/breadcrumbs.html @@ -8,4 +8,4 @@ {% endif %} {% endfor %} - \ No newline at end of file + diff --git a/feincms/templates/content/mediafile/mp3.html b/feincms/templates/content/mediafile/mp3.html index 2bddf3373..6d99a1517 100644 --- a/feincms/templates/content/mediafile/mp3.html +++ b/feincms/templates/content/mediafile/mp3.html @@ -1,6 +1,5 @@

{{ content.mediafile.translation.caption }}

- +

{{ content.mediafile.translation.caption }} (Download)

- diff --git a/feincms/templates/content/richtext/default.html b/feincms/templates/content/richtext/default.html index 6e874ab4f..f0c5340af 100644 --- a/feincms/templates/content/richtext/default.html +++ b/feincms/templates/content/richtext/default.html @@ -1 +1 @@ -{{ content.text|safe }} \ No newline at end of file +{{ content.text|safe }} diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index b055199c7..9167baa2d 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - from django import template from django.template import TemplateSyntaxError from django.template.defaulttags import kwarg_re @@ -69,12 +67,9 @@ def __init__(self, view_name, urlconf, args, kwargs, asvar): def render(self, context): args = [arg.resolve(context) for arg in self.args] - kwargs = dict( - [ - (smart_str(k, "ascii"), v.resolve(context)) - for k, v in self.kwargs.items() - ] - ) + kwargs = { + smart_str(k, "ascii"): v.resolve(context) for k, v in self.kwargs.items() + } view_name = self.view_name.resolve(context) urlconf = self.urlconf.resolve(context) diff --git a/feincms/templatetags/feincms_admin_tags.py b/feincms/templatetags/feincms_admin_tags.py index e8127eb39..253737587 100644 --- a/feincms/templatetags/feincms_admin_tags.py +++ b/feincms/templatetags/feincms_admin_tags.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - from collections import OrderedDict from django import template diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index 60eca87c8..4c5723307 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -1,8 +1,6 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import, unicode_literals import logging import sys @@ -110,7 +108,7 @@ def feincms_nav(context, feincms_page, level=1, depth=1, group=None): if depth > 1: # Filter out children with inactive parents # None (no parent) is always allowed - parents = set([None]) + parents = {None} if parent: # Subset filtering; allow children of parent as well parents.add(parent.id) @@ -217,7 +215,7 @@ def what(self, page, args): # Trailing path without first slash trailing_path = request._feincms_extra_context.get("extra_path", "")[1:] - translations = dict((t.language, t) for t in page.available_translations()) + translations = {t.language: t for t in page.available_translations()} translations[page.language] = page links = [] @@ -254,7 +252,7 @@ def _translate_page_into(page, language, default=None): return page if language is not None: - translations = dict((t.language, t) for t in page.available_translations()) + translations = {t.language: t for t in page.available_translations()} if language in translations: return translations[language] except AttributeError: @@ -311,7 +309,7 @@ def what(self, page, args, default=None): # ------------------------------------------------------------------------ class TranslatedPageNodeOrBase(TranslatedPageNode): def what(self, page, args): - return super(TranslatedPageNodeOrBase, self).what( + return super().what( page, args, default=getattr(page, "get_original_translation", page) ) @@ -451,7 +449,7 @@ def siblings_along_path_to(page_list, page2): for a_page in page_list if a_page.is_ancestor_of(page2, include_self=True) ] - top_level = min((a_page.level for a_page in page_list)) + top_level = min(a_page.level for a_page in page_list) if not ancestors: # Happens when we sit on a page outside the navigation tree so @@ -470,7 +468,7 @@ def siblings_along_path_to(page_list, page2): if ( a_page.parent_id == page2.id or a_page.level == top_level - or any((_is_sibling_of(a_page, a) for a in ancestors)) + or any(_is_sibling_of(a_page, a) for a in ancestors) ) ] diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index faeed6c57..e135e449d 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -1,8 +1,6 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import, unicode_literals import logging @@ -29,7 +27,7 @@ def _render_content(content, **kwargs): level = getattr(request, "feincms_render_level", 0) if level > 10: logging.getLogger("feincms").error( - "Refusing to render %r, render level is already %s" % (content, level) + f"Refusing to render {content!r}, render level is already {level}" ) return setattr(request, "feincms_render_level", level + 1) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index a9a3d54a4..b1479da03 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -1,14 +1,11 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import, unicode_literals import logging import re from io import BytesIO -import six from django import template from django.core.cache import cache from django.core.files.base import ContentFile @@ -23,8 +20,7 @@ register = template.Library() -@six.python_2_unicode_compatible -class Thumbnailer(object): +class Thumbnailer: THUMBNAIL_SIZE_RE = re.compile(r"^(?P\d+)x(?P\d+)$") MARKER = "_thumb_" @@ -34,7 +30,7 @@ def __init__(self, filename, size="200x200"): @property def url(self): - return six.text_type(self) + return str(self) def __str__(self): match = self.THUMBNAIL_SIZE_RE.match(self.size) @@ -88,7 +84,7 @@ def __str__(self): except (NotImplementedError, AttributeError): # storage does NOT support modified_time generate = False - except (OSError, IOError): + except OSError: # Someone might have delete the file return "" diff --git a/feincms/templatetags/fragment_tags.py b/feincms/templatetags/fragment_tags.py index fd8fc4904..dcc1e4e32 100644 --- a/feincms/templatetags/fragment_tags.py +++ b/feincms/templatetags/fragment_tags.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - from django import template @@ -50,7 +48,7 @@ def fragment(parser, token): {% endfragment %} """ - nodelist = parser.parse(("endfragment")) + nodelist = parser.parse("endfragment") parser.delete_first_token() return FragmentNode(nodelist, *token.contents.split()[1:]) diff --git a/feincms/translations.py b/feincms/translations.py index 1104c99df..2255fa4a7 100644 --- a/feincms/translations.py +++ b/feincms/translations.py @@ -28,9 +28,7 @@ class NewsTranslation(Translation(News)): print(news.translation.title) """ -from __future__ import absolute_import, unicode_literals -import six from django.conf import settings from django.contrib import admin from django.core.cache import cache @@ -43,13 +41,11 @@ class NewsTranslation(Translation(News)): from feincms.utils import queryset_transform -class _NoTranslation(object): +class _NoTranslation: """Simple marker for when no translations exist for a certain object Only used for caching.""" - pass - def short_language_code(code=None): """ @@ -170,8 +166,7 @@ def only_language(self, language=short_language_code): ) -@six.python_2_unicode_compatible -class TranslatedObjectMixin(object): +class TranslatedObjectMixin: """ Mixin with helper methods. """ @@ -293,13 +288,13 @@ def short_language_code(self): return short_language_code(self.language_code) def save(self, *args, **kwargs): - super(Inner, self).save(*args, **kwargs) + super().save(*args, **kwargs) self.parent.purge_translation_cache() save.alters_data = True def delete(self, *args, **kwargs): - super(Inner, self).delete(*args, **kwargs) + super().delete(*args, **kwargs) self.parent.purge_translation_cache() delete.alters_data = True diff --git a/feincms/urls.py b/feincms/urls.py index abe5eca1d..d21bde743 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -1,5 +1,4 @@ # flake8: noqa -from __future__ import absolute_import from feincms.views import Handler diff --git a/feincms/utils/__init__.py b/feincms/utils/__init__.py index cd3d6aa73..15ce3c136 100644 --- a/feincms/utils/__init__.py +++ b/feincms/utils/__init__.py @@ -1,13 +1,10 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import, division, unicode_literals import re from importlib import import_module -import six from django.apps import apps from django.core.exceptions import ImproperlyConfigured from django.db.models import AutoField @@ -19,7 +16,7 @@ def get_object(path, fail_silently=False): # Return early if path isn't a string (might already be an callable or # a class or whatever) - if not isinstance(path, six.string_types): # XXX bytes? + if not isinstance(path, str): # XXX bytes? return path try: @@ -86,13 +83,13 @@ def copy_model_instance(obj, exclude=None): """ exclude = exclude or () - initial = dict( - (f.name, getattr(obj, f.name)) + initial = { + f.name: getattr(obj, f.name) for f in obj._meta.fields if not isinstance(f, AutoField) and f.name not in exclude and f not in obj._meta.parents.values() - ) + } return obj.__class__(**initial) @@ -128,15 +125,15 @@ def get_singleton(template_key, cls=None, raise_exception=True): assert model._feincms_templates[template_key].singleton except AttributeError as e: raise ImproperlyConfigured( - "%r does not seem to be a valid FeinCMS base class (%r)" % (model, e) + f"{model!r} does not seem to be a valid FeinCMS base class ({e!r})" ) except KeyError: raise ImproperlyConfigured( - "%r is not a registered template for %r!" % (template_key, model) + f"{template_key!r} is not a registered template for {model!r}!" ) except AssertionError: raise ImproperlyConfigured( - "%r is not a *singleton* template for %r!" % (template_key, model) + f"{template_key!r} is not a *singleton* template for {model!r}!" ) try: return model._default_manager.get(template_key=template_key) diff --git a/feincms/utils/managers.py b/feincms/utils/managers.py index 63d7e9f8f..ffa7d6375 100644 --- a/feincms/utils/managers.py +++ b/feincms/utils/managers.py @@ -1,8 +1,5 @@ -from __future__ import absolute_import, unicode_literals - - # ------------------------------------------------------------------------ -class ActiveAwareContentManagerMixin(object): +class ActiveAwareContentManagerMixin: """ Implement what's necessary to add some kind of "active" state for content objects. The notion of active is defined by a number of filter rules that diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 7ded0c45b..0ca94b0f2 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -81,7 +81,6 @@ def lookup_tags(item_qs): SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ -from __future__ import absolute_import, unicode_literals import django from django.db import models @@ -89,12 +88,12 @@ def lookup_tags(item_qs): class TransformQuerySet(models.query.QuerySet): def __init__(self, *args, **kwargs): - super(TransformQuerySet, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._transform_fns = [] self._orig_iterable_class = getattr(self, "_iterable_class", None) def _clone(self, *args, **kwargs): - c = super(TransformQuerySet, self)._clone(*args, **kwargs) + c = super()._clone(*args, **kwargs) c._transform_fns = self._transform_fns[:] return c @@ -106,7 +105,7 @@ def transform(self, *fn): if django.VERSION < (1, 11): def iterator(self): - result_iter = super(TransformQuerySet, self).iterator() + result_iter = super().iterator() if not self._transform_fns: return result_iter @@ -125,7 +124,7 @@ def iterator(self): else: def _fetch_all(self): - super(TransformQuerySet, self)._fetch_all() + super()._fetch_all() if ( getattr(self, "_iterable_class", None) == self._orig_iterable_class ): # noqa diff --git a/feincms/utils/templatetags.py b/feincms/utils/templatetags.py index 18258b98d..7d1c4632b 100644 --- a/feincms/utils/templatetags.py +++ b/feincms/utils/templatetags.py @@ -9,7 +9,6 @@ {% tag of template_var as var_name arg1,arg2,kwarg3=4 %} """ -from __future__ import absolute_import, unicode_literals from django import template @@ -46,7 +45,7 @@ def _func(parser, token): args = "" except ValueError: raise template.TemplateSyntaxError( - "Invalid syntax for %s node: %s" % (cls.__name__, token.contents) + f"Invalid syntax for {cls.__name__} node: {token.contents}" ) return cls(tag_name, in_var_name, var_name, args) diff --git a/feincms/views/__init__.py b/feincms/views/__init__.py index 014a6adc8..32649f589 100644 --- a/feincms/views/__init__.py +++ b/feincms/views/__init__.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - import logging from django.apps import apps @@ -32,7 +30,7 @@ def get_object(self): def dispatch(self, request, *args, **kwargs): try: - return super(Handler, self).dispatch(request, *args, **kwargs) + return super().dispatch(request, *args, **kwargs) except Http404 as e: if settings.FEINCMS_CMS_404_PAGE is not None: logger.info( @@ -51,7 +49,7 @@ def dispatch(self, request, *args, **kwargs): request.path = request.path_info = settings.FEINCMS_CMS_404_PAGE if hasattr(request, "_feincms_page"): delattr(request, "_feincms_page") - response = super(Handler, self).dispatch( + response = super().dispatch( request, settings.FEINCMS_CMS_404_PAGE, **kwargs ) # Only set status if we actually have a page. If we get for diff --git a/feincms/views/decorators.py b/feincms/views/decorators.py index 9d95dfcde..900c78f29 100644 --- a/feincms/views/decorators.py +++ b/feincms/views/decorators.py @@ -1,10 +1,7 @@ # flake8: noqa -from __future__ import absolute_import, unicode_literals import warnings -from feincms.content.application.models import * - warnings.warn( "Import ApplicationContent and friends from feincms.content.application.models", diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index f0d091392..da843e53c 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -2,7 +2,6 @@ This is a dummy module used to test the ApplicationContent """ -from __future__ import absolute_import, unicode_literals from django.http import HttpResponse, HttpResponseRedirect from django.template.loader import render_to_string @@ -22,7 +21,7 @@ def module_root(request): def args_test(request, kwarg1, kwarg2): - return HttpResponse("%s-%s" % (kwarg1, kwarg2)) + return HttpResponse(f"{kwarg1}-{kwarg2}") def full_reverse_test(request): diff --git a/tests/testapp/models.py b/tests/testapp/models.py index f7acbe0dd..150f8abb8 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -1,6 +1,3 @@ -from __future__ import absolute_import, unicode_literals - -import six from django import forms from django.db import models from django.utils.text import capfirst @@ -83,7 +80,6 @@ def get_admin_fields(form, *args, **kwargs): ) -@six.python_2_unicode_compatible class Category(MPTTModel): name = models.CharField(max_length=20) slug = models.SlugField() diff --git a/tests/testapp/navigation_extensions.py b/tests/testapp/navigation_extensions.py index 6400375fb..bdf89bcc3 100644 --- a/tests/testapp/navigation_extensions.py +++ b/tests/testapp/navigation_extensions.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - from feincms.module.page.extensions.navigation import NavigationExtension, PagePretender @@ -8,8 +6,7 @@ class PassthroughExtension(NavigationExtension): name = "passthrough extension" def children(self, page, **kwargs): - for p in page.children.in_navigation(): - yield p + yield from page.children.in_navigation() class PretenderExtension(NavigationExtension): diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 4a552f553..8c499c4c2 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - import os import django diff --git a/tests/testapp/tests/__init__.py b/tests/testapp/tests/__init__.py index 3972d0e7c..b059a2853 100644 --- a/tests/testapp/tests/__init__.py +++ b/tests/testapp/tests/__init__.py @@ -1,15 +1,7 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ # flake8: noqa -from __future__ import absolute_import - -from .test_cms import * -from .test_extensions import * -from .test_page import * -from .test_stuff import * - # ------------------------------------------------------------------------ diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index f2f9c163d..d2f199f33 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -1,8 +1,6 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import, unicode_literals import django from django.core.exceptions import ImproperlyConfigured @@ -111,7 +109,11 @@ def test_09_related_objects_cache(self): """ class Attachment(models.Model): - base = models.ForeignKey(ExampleCMSBase, related_name="test_related_name") + base = models.ForeignKey( + ExampleCMSBase, + on_delete=models.CASCADE, + related_name="test_related_name", + ) # See issue #323 on Github. ExampleCMSBase._meta._fill_related_objects_cache() @@ -125,7 +127,9 @@ class Attachment(models.Model): # self.assertFalse(hasattr(Attachment, 'anycontents')) class AnyContent(models.Model): - attachment = models.ForeignKey(Attachment, related_name="anycontents") + attachment = models.ForeignKey( + Attachment, on_delete=models.CASCADE, related_name="anycontents" + ) class Meta: abstract = True diff --git a/tests/testapp/tests/test_extensions.py b/tests/testapp/tests/test_extensions.py index add5058e7..e8fc2c3c9 100644 --- a/tests/testapp/tests/test_extensions.py +++ b/tests/testapp/tests/test_extensions.py @@ -1,7 +1,3 @@ -# coding: utf-8 - -from __future__ import absolute_import, unicode_literals - from django.conf import settings as django_settings from django.contrib.sites.models import Site from django.template.defaultfilters import slugify diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 9d5796ee5..b983d2954 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -1,8 +1,6 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import, unicode_literals import os from datetime import datetime, timedelta @@ -133,7 +131,7 @@ def create_page(self, title="Test page", parent=None, **kwargs): title=title, slug=kwargs.get("slug", slugify(title)), parent=parent, - **defaults + **defaults, ) def create_default_page_set(self): @@ -1510,7 +1508,7 @@ def test_33_preview(self): self.login() self.assertEqual(self.client.get(page.get_absolute_url()).status_code, 404) self.assertContains( - self.client.get("%s_preview/%s/" % (page.get_absolute_url(), page.pk)), + self.client.get(f"{page.get_absolute_url()}_preview/{page.pk}/"), "Example content", ) diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index e611651a5..5fca43529 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -1,8 +1,6 @@ # ------------------------------------------------------------------------ -# coding=utf-8 # ------------------------------------------------------------------------ -from __future__ import absolute_import, unicode_literals import doctest from datetime import datetime @@ -18,13 +16,11 @@ # ------------------------------------------------------------------------ -class Empty(object): +class Empty: """ Helper class to use as request substitute (or whatever) """ - pass - class DocTest(TestCase): def test_translation_short_language_code(self): diff --git a/tests/testapp/tests/utils.py b/tests/testapp/tests/utils.py index 5d52b4f5f..c221aedce 100644 --- a/tests/testapp/tests/utils.py +++ b/tests/testapp/tests/utils.py @@ -1,5 +1,3 @@ -# coding: utf-8 - import datetime diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index 9205326a0..0e61da05a 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - import os from django.contrib import admin @@ -13,7 +11,8 @@ try: from django.urls import include, re_path except ImportError: - from django.conf.urls import include, url as re_path + from django.conf.urls import url as re_path + from django.urls import include sitemaps = {"pages": PageSitemap} From 0160ff2a129ff69b977bb07939ac79dd1e7886f6 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 14:25:21 +0100 Subject: [PATCH 1484/1590] CI job list update --- .github/workflows/tests.yml | 25 +++++-------------------- setup.cfg | 21 +++------------------ tox.ini | 30 +++--------------------------- 3 files changed, 11 insertions(+), 65 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 485b7019c..c92b985f3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,11 +14,11 @@ jobs: fail-fast: false matrix: python-version: - - 2.7 - - 3.6 - - 3.7 - - 3.8 - - 3.9 + - "3.6" + - "3.7" + - "3.8" + - "3.9" + - "3.10" steps: - uses: actions/checkout@v2 @@ -33,18 +33,3 @@ jobs: run: | ENV_PREFIX=$(tr -C -d "0-9" <<< "${{ matrix.python-version }}") TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') python -m tox - - lint: - name: Lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - name: Install dependencies - run: | - python -m pip install --upgrade pip tox - - name: Run lint - run: tox -e style diff --git a/setup.cfg b/setup.cfg index 3f7804944..bfa2ac7a9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,13 +18,12 @@ classifiers = License :: OSI Approved :: BSD License Operating System :: OS Independent Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Internet :: WWW/HTTP :: Dynamic Content Topic :: Software Development @@ -33,12 +32,11 @@ classifiers = [options] packages = find: install_requires = - Django>=1.7 + Django>=3.2 Pillow>=2.0.0 django-mptt>=0.7.1 - pytz>=2014.10 six -python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.* +python_requires = >=3.6 include_package_data = True zip_safe = False @@ -49,14 +47,6 @@ exclude = tests tests = coverage -[flake8] -exclude = venv,build,docs,.tox,migrations,migrate -ignore = E203,W503 -max-line-length = 88 - -[wheel] -universal = 1 - [coverage:run] branch = True include = @@ -66,8 +56,3 @@ omit = *migrate* *tests* *.tox* - -[isort] -profile = black -combine_as_imports = True -lines_after_imports = 2 diff --git a/tox.ini b/tox.ini index a1ef2e8d2..87d10122d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,7 @@ [tox] envlist = - py27-dj18-mptt07 - py27-dj19-mptt08 - py27-dj110-mptt08 - py27-dj111-mptt - py{36,37}-dj111-mptt - py{36,37,38,39}-dj{22,30,31,32}-mptt - py{38,39}-dj{main}-mptt - style + py{36,37}-dj{32}-mptt + py{38,39,310}-dj{32,40,main}-mptt [testenv] usedevelop = true @@ -16,25 +10,7 @@ commands = python -Wd {envbindir}/coverage run tests/manage.py test -v2 --keepdb {posargs:testapp} coverage report -m deps = - dj18: Django>=1.8,<1.9 - dj111: Django>=1.11,<2.0 - dj22: Django>=2.2,<3.0 - dj30: Django>=3.0,<3.1 - dj31: Django>=3.1,<3.2 dj32: Django>=3.2,<4.0 + dj32: Django>=4.0,<4.1 djmain: https://github.com/django/django/archive/main.tar.gz - mptt07: django-mptt<0.8 - mptt08: django-mptt<0.9 mptt: django-mptt - -[testenv:style] -deps = - black - flake8 - isort -changedir = {toxinidir} -commands = - black . - isort --profile=black --lines-after-import=2 --combine-as . - flake8 . -skip_install = true From 1c927815743efb42f81a70261e1f2b0d14cd6bbc Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 14:29:33 +0100 Subject: [PATCH 1485/1590] Remove a few unnecessary fallbacks --- feincms/admin/tree_editor.py | 8 +-- feincms/content/application/models.py | 28 +++------ feincms/contrib/preview/urls.py | 5 +- feincms/module/medialibrary/modeladmins.py | 12 +--- feincms/module/page/admin.py | 7 +-- feincms/module/page/modeladmins.py | 14 +---- feincms/module/page/models.py | 8 +-- .../templatetags/applicationcontent_tags.py | 7 +-- feincms/templatetags/feincms_tags.py | 3 - feincms/urls.py | 8 +-- tests/testapp/applicationcontent_urls.py | 7 +-- tests/testapp/tests/test_cms.py | 62 ------------------- tests/testapp/tests/test_page.py | 11 +--- tests/testapp/urls.py | 8 +-- 14 files changed, 22 insertions(+), 166 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index 343e1b8ec..f59f0188a 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -17,6 +17,7 @@ HttpResponseNotFound, HttpResponseServerError, ) +from django.templatetags.static import static from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import gettext, gettext_lazy as _ @@ -28,13 +29,6 @@ from feincms.extensions import ExtensionModelAdmin -try: - # Django<3 - from django.contrib.staticfiles.templatetags.staticfiles import static -except ImportError: - from django.templatetags.static import static - - logger = logging.getLogger(__name__) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 9b885e0bb..2dcb0d150 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -9,31 +9,19 @@ from django.db import models from django.http import HttpResponse from django.template.response import TemplateResponse +from django.urls import ( + NoReverseMatch, + Resolver404, + get_script_prefix, + resolve, + reverse, + set_script_prefix, +) from django.utils.functional import lazy from django.utils.http import http_date from django.utils.safestring import mark_safe from django.utils.translation import get_language, gettext_lazy as _ - -try: - from django.urls import ( - NoReverseMatch, - Resolver404, - get_script_prefix, - resolve, - reverse, - set_script_prefix, - ) -except ImportError: - from django.core.urlresolvers import ( - NoReverseMatch, - reverse, - get_script_prefix, - set_script_prefix, - Resolver404, - resolve, - ) - from feincms.admin.item_editor import ItemEditorForm from feincms.contrib.fields import JSONField from feincms.translations import short_language_code diff --git a/feincms/contrib/preview/urls.py b/feincms/contrib/preview/urls.py index 43d8a4459..bf9f21a7d 100644 --- a/feincms/contrib/preview/urls.py +++ b/feincms/contrib/preview/urls.py @@ -1,7 +1,4 @@ -try: - from django.urls import re_path -except ImportError: - from django.conf.urls import url as re_path +from django.urls import re_path from feincms.contrib.preview.views import PreviewHandler diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index f844ec0b0..e3ff51096 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -13,16 +13,11 @@ from django.http import HttpResponseRedirect from django.shortcuts import render from django.template.defaultfilters import filesizeformat +from django.urls import reverse from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _, ngettext from django.views.decorators.csrf import csrf_protect - -try: - from django.urls import reverse -except ImportError: - from django.core.urlresolvers import reverse - from feincms.extensions import ExtensionModelAdmin from feincms.translations import admin_translationinline, lookup_translations from feincms.utils import shorten_string @@ -124,10 +119,7 @@ class MediaFileAdmin(ExtensionModelAdmin): actions = [assign_category, save_as_zipfile] def get_urls(self): - try: - from django.urls import re_path - except ImportError: - from django.conf.urls import url as re_path + from django.urls import re_path return [ re_path( diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index 29cd42baf..9c5831496 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin -from django.core.exceptions import ImproperlyConfigured +from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured from feincms import ensure_completely_loaded, settings @@ -11,11 +11,6 @@ from .models import Page -try: - from django.core.exceptions import FieldDoesNotExist -except ImportError: # Django<1.8 - from django.db.models import FieldDoesNotExist - # ------------------------------------------------------------------------ if settings.FEINCMS_USE_PAGE_ADMIN: diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 7e261923d..932bfc401 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -10,20 +10,10 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied from django.http import HttpResponseRedirect +from django.templatetags.static import static +from django.urls import reverse from django.utils.translation import gettext_lazy as _ - -try: - from django.urls import reverse -except ImportError: - from django.core.urlresolvers import reverse - -try: - from django.contrib.staticfiles.templatetags.staticfiles import static -except ImportError: - # Newer Django versions. - from django.templatetags.static import static - from feincms import ensure_completely_loaded, settings from feincms.admin import item_editor, tree_editor diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index df7be94ea..de02a7fcf 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -6,14 +6,8 @@ from django.db import models from django.db.models import Q from django.http import Http404 +from django.urls import reverse from django.utils.translation import gettext_lazy as _ - - -try: - from django.urls import reverse -except ImportError: - from django.core.urlresolvers import reverse - from mptt.models import MPTTModel, TreeManager from feincms import settings diff --git a/feincms/templatetags/applicationcontent_tags.py b/feincms/templatetags/applicationcontent_tags.py index 9167baa2d..8fc6ccb63 100644 --- a/feincms/templatetags/applicationcontent_tags.py +++ b/feincms/templatetags/applicationcontent_tags.py @@ -1,14 +1,9 @@ from django import template from django.template import TemplateSyntaxError from django.template.defaulttags import kwarg_re +from django.urls import NoReverseMatch from django.utils.encoding import smart_str - -try: - from django.urls import NoReverseMatch -except ImportError: - from django.core.urlresolvers import NoReverseMatch - from feincms.content.application.models import ( ApplicationContent, app_reverse as do_app_reverse, diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index e135e449d..d7b8817eb 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -43,9 +43,6 @@ def _render_content(content, **kwargs): try: engine = context.template.engine except AttributeError: - # This fails hard in Django 1.7 (ImportError). So what. This - # just means that this particular feature isn't available - # there. from django.template.engine import Engine engine = Engine.get_default() diff --git a/feincms/urls.py b/feincms/urls.py index d21bde743..1094fd6d8 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -1,14 +1,8 @@ -# flake8: noqa +from django.urls import re_path from feincms.views import Handler -try: - from django.urls import re_path -except ImportError: - from django.conf.urls import url as re_path - - handler = Handler.as_view() urlpatterns = [ diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index da843e53c..de3b9ac3e 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -6,16 +6,11 @@ from django.http import HttpResponse, HttpResponseRedirect from django.template.loader import render_to_string from django.template.response import TemplateResponse +from django.urls import re_path from feincms.content.application.models import standalone, unpack -try: - from django.urls import re_path -except ImportError: - from django.conf.urls import url as re_path - - def module_root(request): return HttpResponse("module_root") diff --git a/tests/testapp/tests/test_cms.py b/tests/testapp/tests/test_cms.py index d2f199f33..90c3df88a 100644 --- a/tests/testapp/tests/test_cms.py +++ b/tests/testapp/tests/test_cms.py @@ -1,8 +1,3 @@ -# ------------------------------------------------------------------------ -# ------------------------------------------------------------------------ - - -import django from django.core.exceptions import ImproperlyConfigured from django.db import models from django.test import TestCase @@ -14,16 +9,6 @@ from .test_stuff import Empty -try: - from unittest import skipIf -except ImportError: - from django.utils.unittest import skipIf - -skipUnlessLegacy = skipIf( - django.VERSION >= (1, 8), "Legacy tests only necessary in Django < 1.8" -) - - # ------------------------------------------------------------------------ class SubRawContent(RawContent): title = models.CharField("title", max_length=100, blank=True) @@ -92,53 +77,6 @@ def test_08_creating_two_content_types_in_same_application(self): ct2 = ExampleCMSBase2.content_type_for(RawContent) self.assertEqual(ct2._meta.db_table, "testapp_examplecmsbase2_rawcontent2") - @skipUnlessLegacy - def test_09_related_objects_cache(self): - """ - We need to define a model with relationship to our Base *after* all - content types have been registered; previously _fill_*_cache methods - were called during each content type registration, so any new related - objects added after the last content type time missed the boat. Now we - delete the cache so hopefully _fill_*_cache* won't be called until all - related models have been defined. - - TODO that's a dumb test, we should try being less dynamic instead of - supporting all types of ad-hoc definitions of models etc. - - It also fails on Django 1.7 since the introduction of django.apps - """ - - class Attachment(models.Model): - base = models.ForeignKey( - ExampleCMSBase, - on_delete=models.CASCADE, - related_name="test_related_name", - ) - - # See issue #323 on Github. - ExampleCMSBase._meta._fill_related_objects_cache() - - related_models = map( - lambda x: x.model, ExampleCMSBase._meta.get_all_related_objects() - ) - - self.assertTrue(Attachment in related_models) - self.assertTrue(hasattr(ExampleCMSBase, "test_related_name")) - # self.assertFalse(hasattr(Attachment, 'anycontents')) - - class AnyContent(models.Model): - attachment = models.ForeignKey( - Attachment, on_delete=models.CASCADE, related_name="anycontents" - ) - - class Meta: - abstract = True - - ExampleCMSBase.create_content_type(AnyContent) - - self.assertTrue(hasattr(ExampleCMSBase, "test_related_name")) - self.assertTrue(hasattr(Attachment, "anycontents")) - def test_10_content_type_subclasses(self): """ See: diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index b983d2954..5d23d8ba8 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -16,19 +16,12 @@ from django.template import TemplateDoesNotExist from django.template.defaultfilters import slugify from django.test import TestCase +from django.urls import reverse from django.utils import timezone - -from feincms._internal import force_text - - -try: - from django.urls import reverse -except ImportError: - from django.core.urlresolvers import reverse - from mptt.exceptions import InvalidMove from feincms import settings as feincms_settings +from feincms._internal import force_text from feincms.content.application.models import app_reverse from feincms.contents import RawContent, RichTextContent from feincms.context_processors import add_page_if_missing diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index 0e61da05a..db13f80d1 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -3,18 +3,12 @@ from django.contrib import admin from django.contrib.sitemaps.views import sitemap from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from django.urls import include, re_path from django.views.static import serve from feincms.module.page.sitemap import PageSitemap -try: - from django.urls import include, re_path -except ImportError: - from django.conf.urls import url as re_path - from django.urls import include - - sitemaps = {"pages": PageSitemap} admin.autodiscover() From 6e5b3bce2344f6000eb12442482620e4110ad9c1 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 14:36:56 +0100 Subject: [PATCH 1486/1590] Delete more code, reinit eslint --- .editorconfig | 1 + .eslintrc.js | 7 +- .pre-commit-config.yaml | 8 + feincms/extensions/datepublisher.py | 20 +- package.json | 16 - tests/requirements.txt | 5 - tests/testapp/tests/test_stuff.py | 6 +- tests/tox.ini | 30 -- yarn.lock | 762 ---------------------------- 9 files changed, 18 insertions(+), 837 deletions(-) delete mode 100644 package.json delete mode 100644 tests/requirements.txt delete mode 100644 tests/tox.ini delete mode 100644 yarn.lock diff --git a/.editorconfig b/.editorconfig index fd4bd13c7..5487327b7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,3 +1,4 @@ +# top-most EditorConfig file root = true [*] diff --git a/.eslintrc.js b/.eslintrc.js index 1ad9d3d87..3514ca2af 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,18 +2,15 @@ module.exports = { env: { browser: true, es6: true, + node: true, }, - extends: "eslint:recommended", + extends: ["eslint:recommended", "prettier"], parserOptions: { ecmaVersion: 2018, }, - plugins: ["prettier"], rules: { - indent: ["error", 2], "linebreak-style": ["error", "unix"], - semi: ["error", "always"], "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], - "prettier/prettier": "error", quotes: 0, }, } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2301890d9..9f133eb11 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,3 +37,11 @@ repos: - id: prettier args: [--list-different, --no-semi] exclude: "\\.html$" + - repo: https://github.com/pre-commit/mirrors-eslint + rev: v8.6.0 + hooks: + - id: eslint + additional_dependencies: + - eslint@8.6.0 + - eslint-config-prettier@8.3.0 + exclude: "js.cookie.js|\\.min\\.js$" diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index e23c5512a..d458b89d7 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -17,7 +17,6 @@ from django.utils.cache import patch_response_headers from django.utils.html import mark_safe from django.utils.translation import gettext_lazy as _ -from pytz.exceptions import AmbiguousTimeError from feincms import extensions @@ -53,26 +52,11 @@ def granular_now(n=None, default_tz=None): if n is None: n = timezone.now() if default_tz is None: - default_tz = n.tzinfo - - # Django 1.9: - # The correct way to resolve the AmbiguousTimeError every dst - # transition is... the is_dst parameter appeared with 1.9 - # make_aware(some_datetime, get_current_timezone(), is_dst=True) + default_tz = timezone.get_current_timezone() rounded_minute = (n.minute // 5) * 5 d = datetime(n.year, n.month, n.day, n.hour, rounded_minute) - try: - retval = timezone.make_aware(d, default_tz) - except AmbiguousTimeError: - try: - retval = timezone.make_aware(d, default_tz, is_dst=False) - except TypeError: # Pre-Django 1.9 - retval = timezone.make_aware( - datetime(n.year, n.month, n.day, n.hour + 1, rounded_minute), default_tz - ) - - return retval + return timezone.make_aware(d, default_tz, is_dst=True) # ------------------------------------------------------------------------ diff --git a/package.json b/package.json deleted file mode 100644 index a8d792168..000000000 --- a/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "devDependencies": { - "eslint": "^7.7.0", - "eslint-plugin-prettier": "^3.1.4", - "prettier": "^2.0.5" - }, - "eslintIgnore": [ - "feincms/static/feincms/jquery-1.11.3.min.js", - "feincms/static/feincms/jquery-ui-1.10.3.custom.min.js", - "feincms/static/feincms/js.cookie.js" - ], - "scripts": { - "prettier": "prettier --write .*js feincms/static/feincms/*.*", - "eslint": "eslint feincms/static/feincms/" - } -} diff --git a/tests/requirements.txt b/tests/requirements.txt deleted file mode 100644 index 2c446f486..000000000 --- a/tests/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -Django -django-mptt -Pillow -coverage -pytz diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 5fca43529..033d05d45 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -5,7 +5,6 @@ import doctest from datetime import datetime -import pytz from django.test import TestCase import feincms @@ -74,6 +73,11 @@ def test_shorten_string(self): # ------------------------------------------------------------------------ class TimezoneTest(TestCase): def test_granular_now_dst_transition(self): + try: + import pytz + except ModuleNotFoundError: + return + # Should not raise an exception d = datetime(2016, 10, 30, 2, 10) tz = pytz.timezone("Europe/Copenhagen") diff --git a/tests/tox.ini b/tests/tox.ini deleted file mode 100644 index 69f4a8a20..000000000 --- a/tests/tox.ini +++ /dev/null @@ -1,30 +0,0 @@ -[tox] -setupdir = .. -distribute = False -envlist = - {py26,py27,py32,py33,py34}-django16, - {py27,py33,py34}-django17, - {py27,py34}-django18, - {py27,py34}-django19 - - -[testenv] -commands = - {envpython} manage.py test {posargs:testapp} --settings=testapp.settings -setenv = - PYTHONPATH = .:{toxworkdir}/../.. -deps = - django16: Django>=1.6,<1.7 - django17: Django>=1.7,<1.8 - django18: Django>=1.8,<1.9 - django19: Django>=1.9,<1.10 - feedparser==5.1.3 - Pillow==2.4.0 - pytz==2014.10 - lxml==3.2.3 - {py26,py27,py32,py33,py34}-django16: django-mptt==0.6.0 - {py27,py32,py33,py34}-django17: django-mptt==0.6.1 - {py27,py34}-django18: django-mptt==0.7.1 - {py26,py27}-django{16,17,18}: BeautifulSoup==3.2.1 - {py32,py33,py34}-django{16,17,18}: beautifulsoup4==4.3.1 - {py27,py34}-django{19}: django-mptt==0.8.5 diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 38aea32a1..000000000 --- a/yarn.lock +++ /dev/null @@ -1,762 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" - integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== - -"@babel/highlight@^7.10.4": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" - integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg== - dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@eslint/eslintrc@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" - integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog== - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -acorn-jsx@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== - -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^7.0.2: - version "7.2.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.2.3.tgz#ca78d1cf458d7d36d1c3fa0794dd143406db5772" - integrity sha512-idv5WZvKVXDqKralOImQgPM9v6WOdLNa0IY3B3doOjw/YxRGT8I+allIJ6kd7Uaj+SF1xZUSU+nPM5aDNBVtnw== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^4.0.1, debug@^4.1.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-plugin-prettier@^3.1.4: - version "3.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz#7079cfa2497078905011e6f82e8dd8453d1371b7" - integrity sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" - integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== - -eslint@^7.7.0: - version "7.22.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.22.0.tgz#07ecc61052fec63661a2cab6bd507127c07adc6f" - integrity sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.21" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.4" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" - integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -glob-parent@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globals@^13.6.0: - version "13.7.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.7.0.tgz#aed3bcefd80ad3ec0f0be2cf0c895110c0591795" - integrity sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA== - dependencies: - type-fest "^0.20.2" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lodash@^4.17.20, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.0.5: - version "2.2.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" - integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -semver@^7.2.1: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -table@^6.0.4: - version "6.0.7" - resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" - integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== - dependencies: - ajv "^7.0.2" - lodash "^4.17.20" - slice-ansi "^4.0.0" - string-width "^4.2.0" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From 6e874f9c1761dc2ff6189395177f1769c9aed808 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 14:38:35 +0100 Subject: [PATCH 1487/1590] Oops --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 87d10122d..05db109e2 100644 --- a/tox.ini +++ b/tox.ini @@ -11,6 +11,6 @@ commands = coverage report -m deps = dj32: Django>=3.2,<4.0 - dj32: Django>=4.0,<4.1 + dj40: Django>=4.0,<4.1 djmain: https://github.com/django/django/archive/main.tar.gz mptt: django-mptt From f613e92875a6e225788c87b94ae12417526671de Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 14:46:33 +0100 Subject: [PATCH 1488/1590] Update our usage of force_str, smart_str --- feincms/_internal.py | 10 +--------- feincms/admin/filters.py | 6 +++--- feincms/admin/tree_editor.py | 4 ++-- .../management/commands/medialibrary_orphans.py | 4 ++-- feincms/models.py | 6 +++--- feincms/templatetags/feincms_thumbnail.py | 4 ++-- tests/testapp/tests/test_page.py | 14 +++++++------- tests/testapp/tests/test_stuff.py | 4 ++-- 8 files changed, 22 insertions(+), 30 deletions(-) diff --git a/feincms/_internal.py b/feincms/_internal.py index cea076fb9..23d0d51e9 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -11,7 +11,7 @@ from django.template.loader import render_to_string -__all__ = ("monkeypatch_method", "monkeypatch_property", "force_text", "smart_text") +__all__ = ("monkeypatch_method", "monkeypatch_property") def monkeypatch_method(cls): @@ -61,11 +61,3 @@ def ct_render_to_string(template, ctx, **kwargs): def ct_render_to_string(template, ctx, **kwargs): return render_to_string(template, ctx, request=kwargs.get("request")) - - -# We support older than old versions of Python and Django. Keep the *_text name -# around for a bit longer. -if LooseVersion(get_version()) < LooseVersion("4.0"): - pass -else: - from django.utils.encoding import force_str as force_text, smart_str as smart_text diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index 8a3e09af9..2b1b7add5 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -7,10 +7,10 @@ from django import VERSION as DJANGO_VERSION from django.contrib.admin.filters import ChoicesFieldListFilter from django.db.models import Count +from django.utils.encoding import smart_str from django.utils.safestring import mark_safe from django.utils.translation import gettext as _ -from feincms._internal import smart_text from feincms.utils import shorten_string @@ -57,7 +57,7 @@ def choices(self, cl): yield { "selected": pk == int(self.lookup_val or "0"), "query_string": cl.get_query_string({self.lookup_kwarg: pk}), - "display": mark_safe(smart_text(title)), + "display": mark_safe(smart_str(title)), } def title(self): @@ -106,7 +106,7 @@ def choices(self, cl): yield { "selected": pk == int(self.lookup_val or "0"), "query_string": cl.get_query_string({self.lookup_kwarg: pk}), - "display": mark_safe(smart_text(title)), + "display": mark_safe(smart_str(title)), } def title(self): diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index f59f0188a..d1406d597 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -18,6 +18,7 @@ HttpResponseServerError, ) from django.templatetags.static import static +from django.utils.encoding import force_str from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.translation import gettext, gettext_lazy as _ @@ -25,7 +26,6 @@ from mptt.forms import MPTTAdminForm from feincms import settings -from feincms._internal import force_text from feincms.extensions import ExtensionModelAdmin @@ -533,7 +533,7 @@ def delete_selected_tree(self, modeladmin, request, queryset): if self.has_delete_permission(request, obj): obj.delete() n += 1 - obj_display = force_text(obj) + obj_display = force_str(obj) self.log_deletion(request, obj, obj_display) else: logger.warning( diff --git a/feincms/management/commands/medialibrary_orphans.py b/feincms/management/commands/medialibrary_orphans.py index 0cf787e76..eed34deee 100644 --- a/feincms/management/commands/medialibrary_orphans.py +++ b/feincms/management/commands/medialibrary_orphans.py @@ -1,8 +1,8 @@ import os from django.core.management.base import NoArgsCommand +from django.utils.encoding import force_str -from feincms._internal import force_text from feincms.module.medialibrary.models import MediaFile @@ -16,5 +16,5 @@ def handle_noargs(self, **options): for base, dirs, files in os.walk("media/medialibrary"): for f in files: full = os.path.join(base[6:], f) - if force_text(full) not in mediafiles: + if force_str(full) not in mediafiles: self.stdout.write(os.path.join(base, f)) diff --git a/feincms/models.py b/feincms/models.py index c9c3e6678..6cda0d69a 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -18,10 +18,10 @@ from django.db import connections, models from django.db.models import Q from django.forms.widgets import Media +from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ from feincms import ensure_completely_loaded -from feincms._internal import force_text from feincms.extensions import ExtensionsMixin from feincms.utils import copy_model_instance @@ -39,7 +39,7 @@ def __init__(self, key, title, *args): self._content_types = [] def __str__(self): - return force_text(self.title) + return force_str(self.title) @property def content_types(self): @@ -83,7 +83,7 @@ def _make_region(data): self.regions_dict = {r.key: r for r in self.regions} def __str__(self): - return force_text(self.title) + return force_str(self.title) class ContentProxy: diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index b1479da03..2c774406b 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -10,10 +10,10 @@ from django.core.cache import cache from django.core.files.base import ContentFile from django.core.files.storage import default_storage +from django.utils.encoding import force_str from PIL import Image from feincms import settings -from feincms._internal import force_text logger = logging.getLogger("feincms.templatetags.thumbnail") @@ -49,7 +49,7 @@ def __str__(self): if hasattr(self.filename, "name"): filename = self.filename.name else: - filename = force_text(self.filename) + filename = force_str(self.filename) # defining the filename and the miniature filename try: diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 5d23d8ba8..3dc1159d0 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -18,10 +18,10 @@ from django.test import TestCase from django.urls import reverse from django.utils import timezone +from django.utils.encoding import force_str from mptt.exceptions import InvalidMove from feincms import settings as feincms_settings -from feincms._internal import force_text from feincms.content.application.models import app_reverse from feincms.contents import RawContent, RichTextContent from feincms.context_processors import add_page_if_missing @@ -395,7 +395,7 @@ def test_09_pagecontent(self): self.assertEqual(page2.content.main[0].__class__.__name__, "RawContent") self.assertEqual( - force_text(page2.content.main[0]), + force_str(page2.content.main[0]), "RawContent, region=main," " ordering=0>", ) @@ -418,8 +418,8 @@ def test_10_mediafile_and_imagecontent(self): category = Category.objects.create(title="Category", parent=None) category2 = Category.objects.create(title="Something", parent=category) - self.assertEqual(force_text(category2), "Category - Something") - self.assertEqual(force_text(category), "Category") + self.assertEqual(force_str(category2), "Category - Something") + self.assertEqual(force_str(category), "Category") mediafile = MediaFile.objects.create(file="somefile.jpg") if django.VERSION < (2, 0): @@ -430,21 +430,21 @@ def test_10_mediafile_and_imagecontent(self): mediafile=mediafile, region="main", type="default", ordering=1 ) - self.assertEqual(force_text(mediafile), "somefile.jpg") + self.assertEqual(force_str(mediafile), "somefile.jpg") mediafile.translations.create( caption="something", language_code="%s-ha" % short_language_code() ) mediafile.purge_translation_cache() - self.assertTrue("something" in force_text(mediafile)) + self.assertTrue("something" in force_str(mediafile)) mf = page.content.main[1].mediafile self.assertEqual(mf.translation.caption, "something") self.assertEqual(mf.translation.short_language_code(), short_language_code()) self.assertNotEqual(mf.get_absolute_url(), "") - self.assertEqual(force_text(mf), "something") + self.assertEqual(force_str(mf), "something") self.assertTrue(mf.type == "image") self.assertEqual(MediaFile.objects.only_language("de").count(), 0) diff --git a/tests/testapp/tests/test_stuff.py b/tests/testapp/tests/test_stuff.py index 033d05d45..760d1a22f 100644 --- a/tests/testapp/tests/test_stuff.py +++ b/tests/testapp/tests/test_stuff.py @@ -6,9 +6,9 @@ from datetime import datetime from django.test import TestCase +from django.utils.encoding import force_str import feincms -from feincms._internal import force_text from feincms.extensions.datepublisher import granular_now from feincms.models import Region, Template from feincms.utils import get_object, shorten_string @@ -42,7 +42,7 @@ def test_region(self): # I'm not sure whether this test tests anything at all self.assertEqual(r.key, t.regions[0].key) - self.assertEqual(force_text(r), "region title") + self.assertEqual(force_str(r), "region title") class UtilsTest(TestCase): From b494316442249935ad265d354fc7c369b1118e1f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 14:52:41 +0100 Subject: [PATCH 1489/1590] Drop the ensure_completely_loaded machinery, hopefully not needed anymore --- feincms/__init__.py | 74 ------------------------------ feincms/admin/item_editor.py | 6 --- feincms/models.py | 8 ---- feincms/module/page/admin.py | 3 +- feincms/module/page/forms.py | 4 -- feincms/module/page/modeladmins.py | 4 +- 6 files changed, 2 insertions(+), 97 deletions(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 1c8b3bd4c..9f0502e16 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -23,77 +23,3 @@ def __getattr__(self, attr): settings = LazySettings() - - -COMPLETELY_LOADED = False - - -def ensure_completely_loaded(force=False): - """ - This method ensures all models are completely loaded - - FeinCMS requires Django to be completely initialized before proceeding, - because of the extension mechanism and the dynamically created content - types. - - For more informations, have a look at issue #23 on github: - http://github.com/feincms/feincms/issues#issue/23 - """ - - global COMPLETELY_LOADED - if COMPLETELY_LOADED and not force: - return True - - from django.apps import apps - - if not apps.ready: - return - - # Ensure meta information concerning related fields is up-to-date. - # Upon accessing the related fields information from Model._meta, - # the related fields are cached and never refreshed again (because - # models and model relations are defined upon import time, if you - # do not fumble around with models like we do in FeinCMS.) - # - # Here we flush the caches rather than actually _filling them so - # that relations defined after all content types registrations - # don't miss out. - from distutils.version import LooseVersion - - import django - - if LooseVersion(django.get_version()) < LooseVersion("1.8"): - - for model in apps.get_models(): - for cache_name in ( - "_field_cache", - "_field_name_cache", - "_m2m_cache", - "_related_objects_cache", - "_related_many_to_many_cache", - "_name_map", - ): - try: - delattr(model._meta, cache_name) - except AttributeError: - pass - - # Randomly call some cache filling methods - # http://goo.gl/XNI2qz - model._meta._fill_fields_cache() - - # Calls to get_models(...) are cached by the arguments used in the - # call. This cache is normally cleared in loading.register_models(), - # but we invalidate the get_models() cache, by calling get_models above - # before all apps have loaded. (Django's load_app() doesn't clear the - # get_models cache as it perhaps should). So instead we clear the - # get_models cache again here. If we don't do this, Django 1.5 chokes - # on a model validation error (Django 1.4 doesn't exhibit this - # problem). See Issue #323 on github. - if hasattr(apps, "cache"): - apps.cache.get_models.cache_clear() - - if apps.ready: - COMPLETELY_LOADED = True - - return True diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index a144bb2dc..06cad386a 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -12,7 +12,6 @@ from django.contrib.auth import get_permission_codename from django.http import Http404 -from feincms import ensure_completely_loaded from feincms.extensions import ExtensionModelAdmin from feincms.signals import itemeditor_post_save_related @@ -61,11 +60,6 @@ class ItemEditor(ExtensionModelAdmin): the standard ``ModelAdmin`` class. """ - def __init__(self, model, admin_site): - ensure_completely_loaded() - - super().__init__(model, admin_site) - def get_inline_instances(self, request, *args, **kwargs): inline_instances = super().get_inline_instances(request, *args, **kwargs) self.append_feincms_inlines(inline_instances, request) diff --git a/feincms/models.py b/feincms/models.py index 6cda0d69a..6c756a64e 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -21,7 +21,6 @@ from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ -from feincms import ensure_completely_loaded from feincms.extensions import ExtensionsMixin from feincms.utils import copy_model_instance @@ -411,8 +410,6 @@ def register_templates(cls, *templates): ) def _template(self): - ensure_completely_loaded() - try: return self._feincms_templates[self.template_key] except KeyError: @@ -735,7 +732,6 @@ class Meta(feincms_content_base.Meta): incls ) - ensure_completely_loaded(force=True) return new_type @property @@ -768,8 +764,6 @@ def content_type_for(cls, model): @classmethod def _needs_templates(cls): - ensure_completely_loaded() - # helper which can be used to ensure that either register_regions # or register_templates has been executed before proceeding if not hasattr(cls, "template"): @@ -780,8 +774,6 @@ def _needs_templates(cls): @classmethod def _needs_content_types(cls): - ensure_completely_loaded() - # Check whether any content types have been created for this base # class if not getattr(cls, "_feincms_content_types", None): diff --git a/feincms/module/page/admin.py b/feincms/module/page/admin.py index 9c5831496..a4404b3cb 100644 --- a/feincms/module/page/admin.py +++ b/feincms/module/page/admin.py @@ -5,7 +5,7 @@ from django.contrib import admin from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured -from feincms import ensure_completely_loaded, settings +from feincms import settings from .modeladmins import PageAdmin from .models import Page @@ -14,7 +14,6 @@ # ------------------------------------------------------------------------ if settings.FEINCMS_USE_PAGE_ADMIN: - ensure_completely_loaded() try: Page._meta.get_field("template_key") except FieldDoesNotExist: diff --git a/feincms/module/page/forms.py b/feincms/module/page/forms.py index 64f44ea2e..60b9141c4 100644 --- a/feincms/module/page/forms.py +++ b/feincms/module/page/forms.py @@ -11,8 +11,6 @@ from django.utils.translation import gettext_lazy as _ from mptt.forms import MPTTAdminForm -from feincms import ensure_completely_loaded - class RedirectToWidget(ForeignKeyRawIdWidget): def label_for_value(self, value): @@ -60,8 +58,6 @@ def page_manager(self): return self.page_model._default_manager def __init__(self, *args, **kwargs): - ensure_completely_loaded() - if "initial" in kwargs: if "parent" in kwargs["initial"]: # Prefill a few form values from the parent page diff --git a/feincms/module/page/modeladmins.py b/feincms/module/page/modeladmins.py index 932bfc401..05218e242 100644 --- a/feincms/module/page/modeladmins.py +++ b/feincms/module/page/modeladmins.py @@ -14,7 +14,7 @@ from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from feincms import ensure_completely_loaded, settings +from feincms import settings from feincms.admin import item_editor, tree_editor # ------------------------------------------------------------------------ @@ -70,8 +70,6 @@ def add_extension_options(cls, *f): cls.fieldsets[1][1]["fields"].extend(f) def __init__(self, model, admin_site): - ensure_completely_loaded() - if len(model._feincms_templates) > 4 and "template_key" in self.radio_fields: del self.radio_fields["template_key"] From 9100ad2c564f5500fb957f0ba98d91c1bfee76d8 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 14:53:59 +0100 Subject: [PATCH 1490/1590] Actionbuttons use sprites and cannot use transitions --- feincms/static/feincms/item_editor.css | 1 + 1 file changed, 1 insertion(+) diff --git a/feincms/static/feincms/item_editor.css b/feincms/static/feincms/item_editor.css index 3f80d1539..c6dd1766f 100644 --- a/feincms/static/feincms/item_editor.css +++ b/feincms/static/feincms/item_editor.css @@ -172,6 +172,7 @@ a.actionbutton { float: left; margin: 5px 0 0 20px; text-indent: -7000px; + transition: none; } a.richtextcontent { From 7fbc827b541227e2e843683e087f1655dd68f889 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 15:11:52 +0100 Subject: [PATCH 1491/1590] mptt is implied --- tox.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 05db109e2..cbb197ddd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = - py{36,37}-dj{32}-mptt - py{38,39,310}-dj{32,40,main}-mptt + py{36,37}-dj{32} + py{38,39,310}-dj{32,40,main} [testenv] usedevelop = true @@ -13,4 +13,3 @@ deps = dj32: Django>=3.2,<4.0 dj40: Django>=4.0,<4.1 djmain: https://github.com/django/django/archive/main.tar.gz - mptt: django-mptt From f0d25dccee8948c4f1133441960fc92aa734854e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 15:19:16 +0100 Subject: [PATCH 1492/1590] Make the doctest pass --- feincms/module/medialibrary/models.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index d5651febc..956929b9d 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -172,16 +172,15 @@ def get_absolute_url(self): def determine_file_type(self, name): """ - >>> t = MediaFileBase() - >>> str(t.determine_file_type('foobar.jpg')) + >>> str(MediaFile().determine_file_type('foobar.jpg')) 'image' - >>> str(t.determine_file_type('foobar.PDF')) + >>> str(MediaFile().determine_file_type('foobar.PDF')) 'pdf' - >>> str(t.determine_file_type('foobar.jpg.pdf')) + >>> str(MediaFile().determine_file_type('foobar.jpg.pdf')) 'pdf' - >>> str(t.determine_file_type('foobar.jgp')) + >>> str(MediaFile().determine_file_type('foobar.jgp')) 'other' - >>> str(t.determine_file_type('foobar-jpg')) + >>> str(MediaFile().determine_file_type('foobar-jpg')) 'other' """ for type_key, type_name, type_test in self.filetypes: From 254823c6f17fa53970469bdbb6d4a3b6ac194a2d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 15:32:06 +0100 Subject: [PATCH 1493/1590] Hmm --- tests/testapp/settings.py | 1 + tests/testapp/tests/test_page.py | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 8c499c4c2..c1ac9c160 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -31,6 +31,7 @@ STATIC_ROOT = os.path.join(BASEDIR, "static/") SECRET_KEY = "supersikret" USE_TZ = True +TIME_ZONE = "Europe/Zurich" ROOT_URLCONF = "testapp.urls" LANGUAGES = (("en", "English"), ("de", "German")) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 3dc1159d0..71c92a732 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -118,6 +118,7 @@ def create_page(self, title="Test page", parent=None, **kwargs): "in_navigation": False, "active": False, "navigation_group": "default", + "publication_date": timezone.now() - timedelta(days=1), } defaults.update(kwargs) return Page.objects.create( From d1def22c806d8af1ca0f94c35ffaa8e8e07eb8c0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 15:36:08 +0100 Subject: [PATCH 1494/1590] Fix #633: Also accept the path as a keyword argument --- feincms/views/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feincms/views/__init__.py b/feincms/views/__init__.py index 32649f589..5f0bebcaf 100644 --- a/feincms/views/__init__.py +++ b/feincms/views/__init__.py @@ -22,7 +22,9 @@ def page_model(self): def get_object(self): path = None - if self.args: + if "path" in self.kwargs: + path = self.kwargs["path"] + elif self.args: path = self.args[0] return self.page_model._default_manager.for_request( self.request, raise404=True, best_match=True, path=path From b044d524c0a915a6b711eff1e7a88d13ba50d489 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 16:11:34 +0100 Subject: [PATCH 1495/1590] Remove code for really old versions of Django --- feincms/_internal.py | 20 ++---------- feincms/admin/filters.py | 12 ++----- feincms/admin/item_editor.py | 7 ++-- feincms/contrib/fields.py | 12 ++----- feincms/contrib/tagging.py | 21 +++--------- feincms/module/medialibrary/models.py | 6 +--- .../admin/feincms/content_inline_dj20.html | 31 ------------------ feincms/templatetags/feincms_page_tags.py | 8 ++--- feincms/templatetags/feincms_tags.py | 6 +--- feincms/utils/queryset_transform.py | 32 +++---------------- tests/testapp/settings.py | 20 ------------ tests/testapp/tests/test_page.py | 6 +--- 12 files changed, 22 insertions(+), 159 deletions(-) delete mode 100644 feincms/templates/admin/feincms/content_inline_dj20.html diff --git a/feincms/_internal.py b/feincms/_internal.py index 23d0d51e9..212261b9c 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -5,9 +5,6 @@ """ -from distutils.version import LooseVersion - -from django import get_version from django.template.loader import render_to_string @@ -46,18 +43,5 @@ def decorator(func): return decorator -if LooseVersion(get_version()) < LooseVersion("1.10"): - - def ct_render_to_string(template, ctx, **kwargs): - from django.template import RequestContext - - context_instance = kwargs.get("context") - if context_instance is None and kwargs.get("request"): - context_instance = RequestContext(kwargs["request"]) - - return render_to_string(template, ctx, context_instance=context_instance) - -else: - - def ct_render_to_string(template, ctx, **kwargs): - return render_to_string(template, ctx, request=kwargs.get("request")) +def ct_render_to_string(template, ctx, **kwargs): + return render_to_string(template, ctx, request=kwargs.get("request")) diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index 2b1b7add5..dc77ce9ab 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -4,7 +4,6 @@ # Guilherme M. Gondim (semente) -from django import VERSION as DJANGO_VERSION from django.contrib.admin.filters import ChoicesFieldListFilter from django.db.models import Count from django.utils.encoding import smart_str @@ -75,15 +74,8 @@ def __init__(self, f, request, params, model, model_admin, field_path=None): super().__init__(f, request, params, model, model_admin, field_path) # Restrict results to categories which are actually in use: - if DJANGO_VERSION < (1, 8): - related_model = f.related.parent_model - related_name = f.related.var_name - elif DJANGO_VERSION < (2, 0): - related_model = f.rel.to - related_name = f.related_query_name() - else: - related_model = f.remote_field.model - related_name = f.related_query_name() + related_model = f.remote_field.model + related_name = f.related_query_name() self.lookup_choices = sorted( ( diff --git a/feincms/admin/item_editor.py b/feincms/admin/item_editor.py index 06cad386a..8638c9089 100644 --- a/feincms/admin/item_editor.py +++ b/feincms/admin/item_editor.py @@ -6,7 +6,7 @@ import logging import warnings -from django import VERSION, forms +from django import forms from django.contrib.admin.options import InlineModelAdmin from django.contrib.admin.utils import unquote from django.contrib.auth import get_permission_codename @@ -43,10 +43,7 @@ class FeinCMSInline(InlineModelAdmin): form = ItemEditorForm extra = 0 fk_name = "parent" - if VERSION < (2, 1): - template = "admin/feincms/content_inline_dj20.html" - else: - template = "admin/feincms/content_inline.html" + template = "admin/feincms/content_inline.html" # ------------------------------------------------------------------------ diff --git a/feincms/contrib/fields.py b/feincms/contrib/fields.py index cb46392dd..38f13a714 100644 --- a/feincms/contrib/fields.py +++ b/feincms/contrib/fields.py @@ -1,9 +1,7 @@ import json import logging -from distutils.version import LooseVersion -import six -from django import forms, get_version +from django import forms from django.core.serializers.json import DjangoJSONEncoder from django.db import models @@ -29,13 +27,7 @@ def clean(self, value, *args, **kwargs): return super().clean(value, *args, **kwargs) -if LooseVersion(get_version()) > LooseVersion("1.8"): - workaround_class = models.TextField -else: - workaround_class = six.with_metaclass(models.SubfieldBase, models.TextField) - - -class JSONField(workaround_class): +class JSONField(models.TextField): """ TextField which transparently serializes/unserializes JSON objects diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index eaf2e4c71..35782f642 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -8,7 +8,7 @@ # ------------------------------------------------------------------------ -from django import VERSION, forms +from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple from django.db.models.signals import pre_save from django.utils.translation import gettext_lazy as _ @@ -55,21 +55,10 @@ def clean(self, value): return taglist_to_string(list(value)) -if VERSION >= (1, 10): - - class Tag_formatvalue_mixin: - def format_value(self, value): - value = parse_tag_input(value or "") - return super().format_value(value) - -else: - # _format_value is a private method previous to Django 1.10, - # do the job in render() instead to avoid fiddling with - # anybody's privates - class Tag_formatvalue_mixin: - def render(self, name, value, attrs=None, *args, **kwargs): - value = parse_tag_input(value or "") - return super().render(name, value, attrs, *args, **kwargs) +class Tag_formatvalue_mixin: + def format_value(self, value): + value = parse_tag_input(value or "") + return super().format_value(value) class fv_FilteredSelectMultiple(Tag_formatvalue_mixin, FilteredSelectMultiple): diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 956929b9d..0931bb4a2 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -5,7 +5,6 @@ import os import re -import django from django.db import models from django.db.models.signals import post_delete from django.dispatch.dispatcher import receiver @@ -139,10 +138,7 @@ def register_filetypes(cls, *types): cls.filetypes[0:0] = types choices = [t[0:2] for t in cls.filetypes] cls.filetypes_dict = dict(choices) - if django.VERSION < (1, 9): - cls._meta.get_field("type").choices[:] = choices - else: - cls._meta.get_field("type").choices = choices + cls._meta.get_field("type").choices = choices def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/feincms/templates/admin/feincms/content_inline_dj20.html b/feincms/templates/admin/feincms/content_inline_dj20.html deleted file mode 100644 index 9dd72347c..000000000 --- a/feincms/templates/admin/feincms/content_inline_dj20.html +++ /dev/null @@ -1,31 +0,0 @@ -{% load i18n admin_urls admin_static feincms_admin_tags %} -
-

{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}

-{{ inline_admin_formset.formset.management_form }} -{{ inline_admin_formset.formset.non_form_errors }} - -{% for inline_admin_form in inline_admin_formset %}
-

{{ inline_admin_formset.opts.verbose_name|capfirst }}: {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} {% trans "Change" %}{% endif %} -{% else %}#{{ forloop.counter }}{% endif %} - {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %} - {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}{% endif %} -

- {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} - {% for fieldset in inline_admin_form %} - {% post_process_fieldsets fieldset %} - {% include "admin/includes/fieldset.html" %} - {% endfor %} - {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} - {{ inline_admin_form.fk_field.field }} -
{% endfor %} -
- - diff --git a/feincms/templatetags/feincms_page_tags.py b/feincms/templatetags/feincms_page_tags.py index 4c5723307..5fa5334ff 100644 --- a/feincms/templatetags/feincms_page_tags.py +++ b/feincms/templatetags/feincms_page_tags.py @@ -6,7 +6,6 @@ import sys import traceback -import django from django import template from django.apps import apps from django.conf import settings @@ -23,9 +22,6 @@ logger = logging.getLogger("feincms.templatetags.page") register = template.Library() -assignment_tag = ( - register.simple_tag if django.VERSION >= (1, 9) else register.assignment_tag -) def _get_page_model(): @@ -40,7 +36,7 @@ def format_exception(e): # ------------------------------------------------------------------------ -@assignment_tag(takes_context=True) +@register.simple_tag(takes_context=True) def feincms_nav(context, feincms_page, level=1, depth=1, group=None): """ Saves a list of pages into the given context variable. @@ -482,7 +478,7 @@ def siblings_along_path_to(page_list, page2): # ------------------------------------------------------------------------ -@assignment_tag(takes_context=True) +@register.simple_tag(takes_context=True) def page_is_active(context, page, feincms_page=None, path=None): """ Usage example:: diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index d7b8817eb..97e70c3a1 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -4,7 +4,6 @@ import logging -import django from django import template from django.conf import settings from django.utils.safestring import mark_safe @@ -13,9 +12,6 @@ register = template.Library() -assignment_tag = ( - register.simple_tag if django.VERSION >= (1, 9) else register.assignment_tag -) def _render_content(content, **kwargs): @@ -89,7 +85,7 @@ def feincms_render_content(context, content, request=None): return _render_content(content, request=request, context=context) -@assignment_tag +@register.simple_tag def feincms_load_singleton(template_key, cls=None): """ {% feincms_load_singleton template_key %} -- return a FeinCMS diff --git a/feincms/utils/queryset_transform.py b/feincms/utils/queryset_transform.py index 0ca94b0f2..c7960d79d 100644 --- a/feincms/utils/queryset_transform.py +++ b/feincms/utils/queryset_transform.py @@ -82,7 +82,6 @@ def lookup_tags(item_qs): """ -import django from django.db import models @@ -102,34 +101,11 @@ def transform(self, *fn): c._transform_fns.extend(fn) return c - if django.VERSION < (1, 11): - - def iterator(self): - result_iter = super().iterator() - - if not self._transform_fns: - return result_iter - - if ( - getattr(self, "_iterable_class", None) != self._orig_iterable_class - ): # noqa - # Do not process the result of values() and values_list() - return result_iter - - results = list(result_iter) + def _fetch_all(self): + super()._fetch_all() + if getattr(self, "_iterable_class", None) == self._orig_iterable_class: # noqa for fn in self._transform_fns: - fn(results) - return iter(results) - - else: - - def _fetch_all(self): - super()._fetch_all() - if ( - getattr(self, "_iterable_class", None) == self._orig_iterable_class - ): # noqa - for fn in self._transform_fns: - fn(self._result_cache) + fn(self._result_cache) if hasattr(models.Manager, "from_queryset"): diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index c1ac9c160..c15796d96 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -1,7 +1,5 @@ import os -import django - SITE_ID = 1 @@ -75,21 +73,3 @@ "page": "testapp.migrate.page", "medialibrary": "testapp.migrate.medialibrary", } - -if django.VERSION < (1, 11): - MIDDLEWARE_CLASSES = MIDDLEWARE - -if django.VERSION < (2,): - pass - -elif (2,) <= django.VERSION < (2, 1): - from django.utils import deprecation - - # Anything to make mptt.templatetags.mptt_admin importable - deprecation.RemovedInDjango20Warning = deprecation.RemovedInDjango21Warning - -elif django.VERSION < (3,): - from django.utils import deprecation - - # Anything to make mptt.templatetags.mptt_admin importable - deprecation.RemovedInDjango20Warning = deprecation.RemovedInDjango30Warning diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 71c92a732..3207a6627 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -5,7 +5,6 @@ import os from datetime import datetime, timedelta -import django from django import forms, template from django.conf import settings from django.contrib.auth.models import AnonymousUser, User @@ -423,10 +422,7 @@ def test_10_mediafile_and_imagecontent(self): self.assertEqual(force_str(category), "Category") mediafile = MediaFile.objects.create(file="somefile.jpg") - if django.VERSION < (2, 0): - mediafile.categories = [category] - else: - mediafile.categories.set([category]) + mediafile.categories.set([category]) page.mediafilecontent_set.create( mediafile=mediafile, region="main", type="default", ordering=1 ) From 0217a59e77f26403dcb9e13d0558cd598bec87bd Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 16:19:11 +0100 Subject: [PATCH 1496/1590] Return tuples instead of rendering in all bundled content types --- CHANGELOG.rst | 6 ++++++ feincms/_internal.py | 7 ------- feincms/content/contactform/models.py | 6 ++---- feincms/content/file/models.py | 5 +---- feincms/content/filer/models.py | 5 +---- feincms/content/image/models.py | 5 +---- feincms/content/richtext/models.py | 5 +---- feincms/content/section/models.py | 5 +---- feincms/content/template/models.py | 5 +---- feincms/content/video/models.py | 6 +----- feincms/module/medialibrary/contents.py | 5 +---- tests/testapp/tests/test_page.py | 15 +-------------- 12 files changed, 17 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0370db8e8..35d0a75d2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,12 @@ Change log - Added pre-commit. - Dropped compatibility guarantees with Python < 3.6, Django < 3.2. +- Changed all bundled content types' ``render()`` methods to return the + ``(template_name, context)`` tuple instead of rendering content themselves. +- The default view was changed to accept the path as a ``path`` keyword + argument, not only as a positional argument. +- Changed the item editor action buttons CSS to not use transitions so that the + sprite buttons look as they should. `v1.20.0`_ (2021-03-22) diff --git a/feincms/_internal.py b/feincms/_internal.py index 212261b9c..8c14e15e9 100644 --- a/feincms/_internal.py +++ b/feincms/_internal.py @@ -5,9 +5,6 @@ """ -from django.template.loader import render_to_string - - __all__ = ("monkeypatch_method", "monkeypatch_property") @@ -41,7 +38,3 @@ def decorator(func): return func return decorator - - -def ct_render_to_string(template, ctx, **kwargs): - return render_to_string(template, ctx, request=kwargs.get("request")) diff --git a/feincms/content/contactform/models.py b/feincms/content/contactform/models.py index 5a51568dd..13f63e4f9 100644 --- a/feincms/content/contactform/models.py +++ b/feincms/content/contactform/models.py @@ -13,8 +13,6 @@ from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ -from feincms._internal import ct_render_to_string - class ContactForm(forms.Form): name = forms.CharField(label=_("name")) @@ -42,7 +40,7 @@ def initialize_type(cls, form=None): def process(self, request, **kwargs): if request.GET.get("_cf_thanks"): - self.rendered_output = ct_render_to_string( + self.rendered_output = render_to_string( "content/contactform/thanks.html", {"content": self}, request=request ) return @@ -70,7 +68,7 @@ def process(self, request, **kwargs): form = self.form(initial=initial) - self.rendered_output = ct_render_to_string( + self.rendered_output = render_to_string( "content/contactform/form.html", {"content": self, "form": form}, request=request, diff --git a/feincms/content/file/models.py b/feincms/content/file/models.py index 64ffeb72e..754b4d5f0 100644 --- a/feincms/content/file/models.py +++ b/feincms/content/file/models.py @@ -10,7 +10,6 @@ from django.utils.translation import gettext_lazy as _ from feincms import settings -from feincms._internal import ct_render_to_string class FileContent(models.Model): @@ -30,9 +29,7 @@ class Meta: verbose_name_plural = _("files") def render(self, **kwargs): - return ct_render_to_string( + return ( ["content/file/%s.html" % self.region, "content/file/default.html"], {"content": self}, - request=kwargs.get("request"), - context=kwargs.get("context"), ) diff --git a/feincms/content/filer/models.py b/feincms/content/filer/models.py index 2b4ae5764..6c530ebdb 100644 --- a/feincms/content/filer/models.py +++ b/feincms/content/filer/models.py @@ -3,7 +3,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from feincms._internal import ct_render_to_string from feincms.admin.item_editor import FeinCMSInline @@ -36,7 +35,7 @@ class Meta: abstract = True def render(self, **kwargs): - return ct_render_to_string( + return ( [ f"content/filer/{self.file_type}_{self.type}.html", "content/filer/%s.html" % self.type, @@ -44,8 +43,6 @@ def render(self, **kwargs): "content/filer/default.html", ], {"content": self}, - request=kwargs.get("request"), - context=kwargs.get("context"), ) class FilerFileContent(ContentWithFilerFile): diff --git a/feincms/content/image/models.py b/feincms/content/image/models.py index fbf83171a..bd7f70a99 100644 --- a/feincms/content/image/models.py +++ b/feincms/content/image/models.py @@ -10,7 +10,6 @@ from django.utils.translation import gettext_lazy as _ from feincms import settings -from feincms._internal import ct_render_to_string from feincms.templatetags import feincms_thumbnail @@ -64,11 +63,9 @@ def render(self, **kwargs): if hasattr(self, "position"): templates.insert(0, "content/image/%s.html" % self.position) - return ct_render_to_string( + return ( templates, {"content": self}, - request=kwargs.get("request"), - context=kwargs.get("context"), ) def get_image(self): diff --git a/feincms/content/richtext/models.py b/feincms/content/richtext/models.py index b3809de80..023e854dc 100644 --- a/feincms/content/richtext/models.py +++ b/feincms/content/richtext/models.py @@ -2,7 +2,6 @@ from django.utils.translation import gettext_lazy as _ from feincms import settings -from feincms._internal import ct_render_to_string from feincms.contrib.richtext import RichTextField @@ -30,11 +29,9 @@ class Meta: verbose_name_plural = _("rich texts") def render(self, **kwargs): - return ct_render_to_string( + return ( "content/richtext/default.html", {"content": self}, - request=kwargs.get("request"), - context=kwargs.get("context"), ) @classmethod diff --git a/feincms/content/section/models.py b/feincms/content/section/models.py index 8fee106df..d21c8f083 100644 --- a/feincms/content/section/models.py +++ b/feincms/content/section/models.py @@ -5,7 +5,6 @@ from django.utils.translation import gettext_lazy as _ from feincms import settings -from feincms._internal import ct_render_to_string from feincms.admin.item_editor import FeinCMSInline from feincms.contrib.richtext import RichTextField from feincms.module.medialibrary.fields import MediaFileForeignKey @@ -81,7 +80,7 @@ def render(self, **kwargs): else: mediafile_type = "nomedia" - return ct_render_to_string( + return ( [ f"content/section/{mediafile_type}_{self.type}.html", "content/section/%s.html" % mediafile_type, @@ -89,8 +88,6 @@ def render(self, **kwargs): "content/section/default.html", ], {"content": self}, - request=kwargs.get("request"), - context=kwargs.get("context"), ) def save(self, *args, **kwargs): diff --git a/feincms/content/template/models.py b/feincms/content/template/models.py index 805cd0ae9..65df1a8da 100644 --- a/feincms/content/template/models.py +++ b/feincms/content/template/models.py @@ -1,7 +1,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from feincms._internal import ct_render_to_string from feincms.content.raw.models import RawContent # noqa from feincms.content.richtext.models import RichTextContent # noqa @@ -31,9 +30,7 @@ def initialize_type(cls, TEMPLATES): ) def render(self, **kwargs): - return ct_render_to_string( + return ( self.template, {"content": self}, - request=kwargs.get("request"), - context=kwargs.get("context"), ) diff --git a/feincms/content/video/models.py b/feincms/content/video/models.py index 2445278cf..339932042 100644 --- a/feincms/content/video/models.py +++ b/feincms/content/video/models.py @@ -3,8 +3,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from feincms._internal import ct_render_to_string - class VideoContent(models.Model): """ @@ -71,9 +69,7 @@ def ctx_for_video(self, vurl): def render(self, **kwargs): ctx = self.ctx_for_video(self.video) - return ct_render_to_string( + return ( self.get_templates(ctx["portal"]), ctx, - request=kwargs.get("request"), - context=kwargs.get("context"), ) diff --git a/feincms/module/medialibrary/contents.py b/feincms/module/medialibrary/contents.py index f1e17d959..9c875783c 100644 --- a/feincms/module/medialibrary/contents.py +++ b/feincms/module/medialibrary/contents.py @@ -3,7 +3,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from feincms._internal import ct_render_to_string from feincms.admin.item_editor import FeinCMSInline from feincms.module.medialibrary.fields import ContentWithMediaFile @@ -63,7 +62,7 @@ def initialize_type(cls, TYPE_CHOICES=None): ) def render(self, **kwargs): - return ct_render_to_string( + return ( [ f"content/mediafile/{self.mediafile.type}_{self.type}.html", "content/mediafile/%s.html" % self.mediafile.type, @@ -71,6 +70,4 @@ def render(self, **kwargs): "content/mediafile/default.html", ], {"content": self}, - request=kwargs.get("request"), - context=kwargs.get("context"), ) diff --git a/tests/testapp/tests/test_page.py b/tests/testapp/tests/test_page.py index 3207a6627..8868a99ac 100644 --- a/tests/testapp/tests/test_page.py +++ b/tests/testapp/tests/test_page.py @@ -22,7 +22,7 @@ from feincms import settings as feincms_settings from feincms.content.application.models import app_reverse -from feincms.contents import RawContent, RichTextContent +from feincms.contents import RawContent from feincms.context_processors import add_page_if_missing from feincms.models import ContentProxy from feincms.module.medialibrary.models import Category, MediaFile @@ -592,19 +592,6 @@ def test_13_inheritance_and_ct_tracker(self): self.assertNotEqual(page2._ct_inventory, {}) - def test_14_richtext(self): - # only create the content type to test the item editor - # customization hooks - tmp = Page._feincms_content_types[:] - type = Page.create_content_type(RichTextContent, regions=("notexists",)) - Page._feincms_content_types = tmp - - from django.utils.safestring import SafeData - - obj = type() - obj.text = "Something" - self.assertTrue(isinstance(obj.render(), SafeData)) - def test_17_page_template_tags(self): self.create_default_page_set() From be35576fa86083a969ae56aaf848173d1a5a3c5d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 7 Jan 2022 16:41:29 +0100 Subject: [PATCH 1497/1590] FeinCMS v22.0.0 --- CHANGELOG.rst | 11 ++++++++--- feincms/__init__.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 35d0a75d2..46c485d87 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,10 +6,14 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ -- Added pre-commit. -- Dropped compatibility guarantees with Python < 3.6, Django < 3.2. + +`v22.0.0`_ (2022-01-07) +~~~~~~~~~~~~~~~~~~~~~~~ + - Changed all bundled content types' ``render()`` methods to return the ``(template_name, context)`` tuple instead of rendering content themselves. +- Dropped compatibility guarantees with Python < 3.6, Django < 3.2. +- Added pre-commit. - The default view was changed to accept the path as a ``path`` keyword argument, not only as a positional argument. - Changed the item editor action buttons CSS to not use transitions so that the @@ -124,4 +128,5 @@ Change log .. _v1.18.0: https://github.com/feincms/feincms/compare/v1.17.0...v1.18.0 .. _v1.19.0: https://github.com/feincms/feincms/compare/v1.18.0...v1.19.0 .. _v1.20.0: https://github.com/feincms/feincms/compare/v1.19.0...v1.20.0 -.. _Next version: https://github.com/feincms/feincms/compare/v1.20.0...master +.. _v22.0.0: https://github.com/feincms/feincms/compare/v1.20.0...v22.0.0 +.. _Next version: https://github.com/feincms/feincms/compare/v22.0.0...master diff --git a/feincms/__init__.py b/feincms/__init__.py index 9f0502e16..6f0339638 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 20, 1) +VERSION = (22, 0, 0) __version__ = ".".join(map(str, VERSION)) From 71c2224b9f13b8b0d20a710712185987dc0b3c33 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 11 Jan 2022 17:07:15 +0100 Subject: [PATCH 1498/1590] Fix the recursion protection --- CHANGELOG.rst | 2 ++ feincms/templatetags/feincms_tags.py | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 46c485d87..8cdde02fd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,8 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ +- Fixed the ``feincms_render_level`` render recursion protection. + `v22.0.0`_ (2022-01-07) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/feincms/templatetags/feincms_tags.py b/feincms/templatetags/feincms_tags.py index 97e70c3a1..2a1849d1a 100644 --- a/feincms/templatetags/feincms_tags.py +++ b/feincms/templatetags/feincms_tags.py @@ -30,6 +30,10 @@ def _render_content(content, **kwargs): r = content.render(**kwargs) + if request is not None: + level = getattr(request, "feincms_render_level", 1) + setattr(request, "feincms_render_level", max(level - 1, 0)) + if isinstance(r, (list, tuple)): # Modeled after feincms3's TemplatePluginRenderer context = kwargs["context"] @@ -51,10 +55,6 @@ def _render_content(content, **kwargs): with context.push(plugin_context): return plugin_template.render(context) - if request is not None: - level = getattr(request, "feincms_render_level", 1) - setattr(request, "feincms_render_level", max(level - 1, 0)) - return r From 41cedbb7d390e32982f983e9fd8caeed45db0212 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 11 Jan 2022 17:08:51 +0100 Subject: [PATCH 1499/1590] FeinCMS v22.0.1 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 6f0339638..e6d5c4a77 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (22, 0, 0) +VERSION = (22, 0, 1) __version__ = ".".join(map(str, VERSION)) From 94dc079d6a75ea47ca650dfc48607ca8e4508db3 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 09:19:00 +0100 Subject: [PATCH 1500/1590] Do not use dict.items() if we don't need the key, use dict.values() --- feincms/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index 6c756a64e..dbc0b9b2f 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -232,7 +232,7 @@ def _fetch_regions(self): if "regions" not in self._cache: self._populate_content_type_caches(self.item._feincms_content_types) contents = {} - for cls, content_list in self._cache["cts"].items(): + for content_list in self._cache["cts"].values(): for instance in content_list: contents.setdefault(instance.region, []).append(instance) From 5b4727119cfbed22e11912f2646cb2b90390a353 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 09:19:38 +0100 Subject: [PATCH 1501/1590] Wrap cursor use in with statement, this fixes leaking cursors (no real impact though) --- feincms/models.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index dbc0b9b2f..bf71d0002 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -173,13 +173,12 @@ def _fetch_content_type_count_helper(self, pk, regions=None): ) sql = "SELECT * FROM ( " + sql + " ) AS ct ORDER BY ct_idx" - cursor = connections[self.db].cursor() - cursor.execute(sql, args) - _c = {} - for ct_idx, region, count in cursor.fetchall(): - if count: - _c.setdefault(region, []).append((pk, ct_idx)) + with connections[self.db].cursor() as cursor: + cursor.execute(sql, args) + for ct_idx, region, count in cursor.fetchall(): + if count: + _c.setdefault(region, []).append((pk, ct_idx)) return _c From b771f8d9a426f64762905539e9ef108a2ece464d Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 09:20:20 +0100 Subject: [PATCH 1502/1590] On Page save(), wrap updating child _cached_url into a transaction, so if anything fails we have a consistent state. --- feincms/module/page/models.py | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/feincms/module/page/models.py b/feincms/module/page/models.py index de02a7fcf..01c0da108 100644 --- a/feincms/module/page/models.py +++ b/feincms/module/page/models.py @@ -3,7 +3,7 @@ from django.core.exceptions import PermissionDenied -from django.db import models +from django.db import models, transaction from django.db.models import Q from django.http import Http404 from django.urls import reverse @@ -264,29 +264,29 @@ def save(self, *args, **kwargs): self._cached_url = f"{self.parent._cached_url}{self.slug}/" cached_page_urls[self.id] = self._cached_url - super().save(*args, **kwargs) - # If our cached URL changed we need to update all descendants to - # reflect the changes. Since this is a very expensive operation - # on large sites we'll check whether our _cached_url actually changed - # or if the updates weren't navigation related: - if self._cached_url == self._original_cached_url: - return - - pages = self.get_descendants().order_by("lft") - - for page in pages: - if page.override_url: - page._cached_url = page.override_url - else: - # cannot be root node by definition - page._cached_url = "{}{}/".format( - cached_page_urls[page.parent_id], - page.slug, - ) - - cached_page_urls[page.id] = page._cached_url - super(BasePage, page).save() # do not recurse + with transaction.atomic(): + super().save(*args, **kwargs) + + # If our cached URL changed we need to update all descendants to + # reflect the changes. Since this is a very expensive operation + # on large sites we'll check whether our _cached_url actually changed + # or if the updates weren't navigation related: + if self._cached_url != self._original_cached_url: + pages = self.get_descendants().order_by("lft") + + for page in pages: + if page.override_url: + page._cached_url = page.override_url + else: + # cannot be root node by definition + page._cached_url = "{}{}/".format( + cached_page_urls[page.parent_id], + page.slug, + ) + + cached_page_urls[page.id] = page._cached_url + super(BasePage, page).save() # do not recurse save.alters_data = True From 237e84d38e59e5fcca9d00673806ed3a2f3433f2 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 09:43:24 +0100 Subject: [PATCH 1503/1590] Remove Django 1.x compat --- feincms/models.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index bf71d0002..50c2a7e90 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -424,13 +424,7 @@ def _template(self): (template_.key, template_.title) for template_ in cls._feincms_templates.values() ] - try: - # noqa https://github.com/django/django/commit/80e3444eca045799cc40e50c92609e852a299d38 - # Django 1.9 uses this code - field.choices = cls.TEMPLATE_CHOICES - except AttributeError: - # Older versions of Django use that. - field._choices = cls.TEMPLATE_CHOICES + field.choices = cls.TEMPLATE_CHOICES field.default = cls.TEMPLATE_CHOICES[0][0] # Build a set of all regions used anywhere From 9ed6b7b9d86344ae1176504b018a5c60944042c6 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 09:44:18 +0100 Subject: [PATCH 1504/1590] Remove Django 1.0 compat; Move static class definition out of function. --- feincms/module/page/processors.py | 36 +++++++++++++------------------ 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 545500588..070257c42 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -4,6 +4,7 @@ from django.conf import settings as django_settings from django.http import Http404, HttpResponseRedirect +from django.views.decorators.http import condition logger = logging.getLogger(__name__) @@ -51,29 +52,26 @@ def extra_context_request_processor(page, request): ) -def etag_request_processor(page, request): +class __DummyResponse(dict): """ - Short-circuits the request-response cycle if the ETag matches. + This is a dummy class with enough behaviour of HttpResponse so we + can use the condition decorator without too much pain. """ - # XXX is this a performance concern? Does it create a new class - # every time the processor is called or is this optimized to a static - # class?? - class DummyResponse(dict): - """ - This is a dummy class with enough behaviour of HttpResponse so we - can use the condition decorator without too much pain. - """ + @property + def headers(self): + return self - @property - def headers(self): - return self + def has_header(self, what): + return False - def has_header(page, what): - return False +def etag_request_processor(page, request): + """ + Short-circuits the request-response cycle if the ETag matches. + """ def dummy_response_handler(*args, **kwargs): - return DummyResponse() + return __DummyResponse() def etagger(request, page, *args, **kwargs): etag = page.etag(request) @@ -83,10 +81,6 @@ def lastmodifier(request, page, *args, **kwargs): lm = page.last_modified() return lm - # Unavailable in Django 1.0 -- the current implementation of ETag support - # requires Django 1.1 unfortunately. - from django.views.decorators.http import condition - # Now wrap the condition decorator around our dummy handler: # the net effect is that we will be getting a DummyResponse from # the handler if processing is to continue and a non-DummyResponse @@ -97,7 +91,7 @@ def lastmodifier(request, page, *args, **kwargs): # If dummy then don't do anything, if a real response, return and # thus shortcut the request processing. - if not isinstance(rsp, DummyResponse): + if not isinstance(rsp, __DummyResponse): return rsp From 38d335e3f19823580ee5249ddc37eae5e4fb9218 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 10:40:54 +0100 Subject: [PATCH 1505/1590] Optimize query for ContentType mapping, use get_for_models() to fetch all CTs at once --- feincms/extensions/ct_tracker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/extensions/ct_tracker.py b/feincms/extensions/ct_tracker.py index f99df4e2e..02cb667a0 100644 --- a/feincms/extensions/ct_tracker.py +++ b/feincms/extensions/ct_tracker.py @@ -84,8 +84,9 @@ def _translation_map(self): # information is ready, especially when we are doing a "syncdb" the # ContentType table does not yet exist map = {} + model_to_contenttype = ContentType.objects.get_for_models(*self.item._feincms_content_types) for idx, fct in enumerate(self.item._feincms_content_types): - dct = ContentType.objects.get_for_model(fct) + dct = model_to_contenttype[fct] # Rely on non-negative primary keys map[-dct.id] = idx # From-inventory map From 2714b2caabde56d6c13bbc7f9528e1677ed1097f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Mar 2022 14:57:27 +0100 Subject: [PATCH 1506/1590] Only purge the translation cache after the initial save --- feincms/module/medialibrary/modeladmins.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index e3ff51096..40639a4bc 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -232,7 +232,8 @@ def get_queryset(self, request): return super().get_queryset(request).transform(lookup_translations()) def save_model(self, request, obj, form, change): - obj.purge_translation_cache() + if obj.id: + obj.purge_translation_cache() return super().save_model(request, obj, form, change) From 928d95e526deb552b69aae7a4c0d805b16a3dcc9 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 15 Mar 2022 14:58:13 +0100 Subject: [PATCH 1507/1590] Run pre-commit on all files --- feincms/extensions/ct_tracker.py | 4 +++- feincms/module/page/processors.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/feincms/extensions/ct_tracker.py b/feincms/extensions/ct_tracker.py index 02cb667a0..f466577cd 100644 --- a/feincms/extensions/ct_tracker.py +++ b/feincms/extensions/ct_tracker.py @@ -84,7 +84,9 @@ def _translation_map(self): # information is ready, especially when we are doing a "syncdb" the # ContentType table does not yet exist map = {} - model_to_contenttype = ContentType.objects.get_for_models(*self.item._feincms_content_types) + model_to_contenttype = ContentType.objects.get_for_models( + *self.item._feincms_content_types + ) for idx, fct in enumerate(self.item._feincms_content_types): dct = model_to_contenttype[fct] diff --git a/feincms/module/page/processors.py b/feincms/module/page/processors.py index 070257c42..6b8016b77 100644 --- a/feincms/module/page/processors.py +++ b/feincms/module/page/processors.py @@ -65,6 +65,7 @@ def headers(self): def has_header(self, what): return False + def etag_request_processor(page, request): """ Short-circuits the request-response cycle if the ETag matches. From 8d94530aa177f7bc2b5f85dc667a20d3306e7f66 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 15:20:10 +0100 Subject: [PATCH 1508/1590] tagging.register is no more since 2015. --- feincms/contrib/tagging.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index 35782f642..f1b5c767a 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -12,15 +12,11 @@ from django.contrib.admin.widgets import FilteredSelectMultiple from django.db.models.signals import pre_save from django.utils.translation import gettext_lazy as _ + from tagging.fields import TagField from tagging.models import Tag from tagging.utils import parse_tag_input - - -try: - from tagging.registry import AlreadyRegistered -except ImportError: - from tagging import AlreadyRegistered +from tagging.registry import AlreadyRegistered, register as tagging_register # ------------------------------------------------------------------------ @@ -122,10 +118,6 @@ def tag_model( auto_add_admin_field If True, attempts to add the tag field to the admin class. """ - try: - from tagging.registry import register as tagging_register - except ImportError: - from tagging import register as tagging_register cls.add_to_class( field_name, From f87edde82086e8c7faca9dbd2b8f07b8eb3612dd Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 15:21:07 +0100 Subject: [PATCH 1509/1590] NoArgsCommand was removed in Dj 1.10 --- feincms/management/commands/rebuild_mptt.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index d2479384d..df52c1ae7 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -8,11 +8,7 @@ """ -try: - from django.core.management.base import NoArgsCommand as BaseCommand -except ImportError: - from django.core.management.base import BaseCommand - +from django.core.management.base import BaseCommand from feincms.module.page.models import Page From bbb3f14b245e39942189441410e299159b6b5886 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 15:45:27 +0100 Subject: [PATCH 1510/1590] Make docs reflect branch name reality (and CI testing reality too) --- CHANGELOG.rst | 2 +- README.rst | 4 ++-- docs/contributing.rst | 4 ++-- docs/installation.rst | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8cdde02fd..de0c2a421 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -131,4 +131,4 @@ Change log .. _v1.19.0: https://github.com/feincms/feincms/compare/v1.18.0...v1.19.0 .. _v1.20.0: https://github.com/feincms/feincms/compare/v1.19.0...v1.20.0 .. _v22.0.0: https://github.com/feincms/feincms/compare/v1.20.0...v22.0.0 -.. _Next version: https://github.com/feincms/feincms/compare/v22.0.0...master +.. _Next version: https://github.com/feincms/feincms/compare/v22.0.0...main diff --git a/README.rst b/README.rst index cf9cf1901..9bd5832ff 100644 --- a/README.rst +++ b/README.rst @@ -87,9 +87,9 @@ The FeinCMS repository on github has several branches. Their purpose and rewinding policies are described below. * ``maint``: Maintenance branch for the second-newest version of FeinCMS. -* ``master``: Stable version of FeinCMS. +* ``main``: Stable version of FeinCMS. -``master`` and ``maint`` are never rebased or rewound. +``main`` and ``maint`` are never rebased or rewound. * ``next``: Upcoming version of FeinCMS. This branch is rarely rebased if ever, but this might happen. A note will be sent to the official diff --git a/docs/contributing.rst b/docs/contributing.rst index 7f9ca1991..4feed80a0 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -12,9 +12,9 @@ The FeinCMS repository on github has several branches. Their purpose and rewinding policies are described below. * ``maint``: Maintenance branch for the second-newest version of FeinCMS. -* ``master``: Stable version of FeinCMS. +* ``main``: Stable version of FeinCMS. -``master`` and ``maint`` are never rebased or rewound. +``main`` and ``maint`` are never rebased or rewound. * ``next``: Upcoming version of FeinCMS. This branch is rarely rebased if ever, but this might happen. A note will be sent to the official diff --git a/docs/installation.rst b/docs/installation.rst index 6850d2ca3..e607bccf2 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -16,8 +16,8 @@ You can download a stable release of FeinCMS using ``pip``. Pip will install feincms and its dependencies. Dependencies which are automatically installed are: feedparser_, Pillow_ and django-mptt_. For outdated versions of Django the best place to find supported combinations of library versions is the -`Travis CI build configuration -`_. +`tox build configuration +`_. $ pip install feincms From 43bc0201cb67053824a0b0c67d98eb2850c28c30 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 16:10:07 +0100 Subject: [PATCH 1511/1590] Make medialibrary_orphans work again --- .../commands/medialibrary_orphans.py | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/feincms/management/commands/medialibrary_orphans.py b/feincms/management/commands/medialibrary_orphans.py index eed34deee..208d47213 100644 --- a/feincms/management/commands/medialibrary_orphans.py +++ b/feincms/management/commands/medialibrary_orphans.py @@ -1,20 +1,24 @@ import os -from django.core.management.base import NoArgsCommand -from django.utils.encoding import force_str +from django.conf import settings +from django.core.management.base import BaseCommand from feincms.module.medialibrary.models import MediaFile -class Command(NoArgsCommand): +class Command(BaseCommand): help = "Prints all orphaned files in the `media/medialibrary` folder" - def handle_noargs(self, **options): + def handle(self, **options): mediafiles = list(MediaFile.objects.values_list("file", flat=True)) - # TODO make this smarter, and take MEDIA_ROOT into account - for base, dirs, files in os.walk("media/medialibrary"): + root_len = len(settings.MEDIA_ROOT) + medialib_path = os.path.join(settings.MEDIA_ROOT, "medialibrary") + + for base, dirs, files in os.walk(medialib_path): for f in files: - full = os.path.join(base[6:], f) - if force_str(full) not in mediafiles: - self.stdout.write(os.path.join(base, f)) + if base.startswith(settings.MEDIA_ROOT): + base = base[root_len:] + full = os.path.join(base, f) + if full not in mediafiles: + self.stdout.write(full) From 5e07a651789ddb69575abf030b6703d22d0c1866 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 16:13:30 +0100 Subject: [PATCH 1512/1590] medialibrary_to_filer, use BaseCommand (otherwise untested though). --- feincms/management/commands/medialibrary_to_filer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/management/commands/medialibrary_to_filer.py b/feincms/management/commands/medialibrary_to_filer.py index 137084a1d..52ef3d4f4 100644 --- a/feincms/management/commands/medialibrary_to_filer.py +++ b/feincms/management/commands/medialibrary_to_filer.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import User from django.core.files import File as DjangoFile -from django.core.management.base import NoArgsCommand +from django.core.management.base import BaseCommand from filer.models import File, Image from feincms.contents import FilerFileContent, FilerImageContent @@ -19,10 +19,10 @@ ), "Not all required models available" -class Command(NoArgsCommand): +class Command(BaseCommand): help = "Migrate the medialibrary and contents to django-filer" - def handle_noargs(self, **options): + def handle(self, **options): user = User.objects.order_by("pk")[0] count = MediaFile.objects.count() From 7e2f9ec6214eea4614ca3a9d6cccfbe73c03c485 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 21:19:09 +0100 Subject: [PATCH 1513/1590] No more need for six.py_2_unicode_compatible --- feincms/models.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 50c2a7e90..359ef862e 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -12,7 +12,6 @@ from collections import OrderedDict from functools import reduce -import six from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured from django.db import connections, models @@ -535,9 +534,7 @@ def get_queryset(cls, filter_args): RuntimeWarning, ) - cls._feincms_content_model = six.python_2_unicode_compatible( - type(str(name), (models.Model,), attrs) - ) + cls._feincms_content_model = type(str(name), (models.Model,), attrs) # list of concrete content types cls._feincms_content_types = [] From dfacdbe51058f2afc032b7cb63cba3344393c57e Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 21:21:08 +0100 Subject: [PATCH 1514/1590] Small optimisation: More often than not _populate_content_type_cache is called from _fetch_regions, and passes in the whole _feincms_content_types. No need to resolve that using itself into itself. --- feincms/models.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/feincms/models.py b/feincms/models.py index 359ef862e..42b2de89d 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -194,11 +194,16 @@ def _populate_content_type_caches(self, types): ).append((region, pk)) # Resolve abstract to concrete content types - content_types = ( - cls - for cls in self.item._feincms_content_types - if issubclass(cls, tuple(types)) - ) + if types is self.item._feincms_content_types: + # If we come from _fetch_regions, we don't need to do + # any type resolving + content_types = self.item._feincms_content_types + else: + content_types = ( + cls + for cls in self.item._feincms_content_types + if issubclass(cls, tuple(types)) + ) for cls in content_types: counts = counts_by_type.get(cls) From 8a0b8d3e435bb06544840eac6ac5d64ece8ee49a Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 21:21:41 +0100 Subject: [PATCH 1515/1590] Another dict.values instead of dict.items and discarding the key --- feincms/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/models.py b/feincms/models.py index 42b2de89d..42a133c1f 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -223,7 +223,7 @@ def _populate_content_type_caches(self, types): # share this content proxy object between all content items # so that each can use obj.parent.content to determine its # relationship to its siblings, etc. - for cls, objects in self._cache["cts"].items(): + for objects in self._cache["cts"].values(): for obj in objects: setattr(obj.parent, "_content_proxy", self) From 77ca78acbcd9ef16fa1d2b656e14b50175184ada Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 15 Mar 2022 22:05:00 +0100 Subject: [PATCH 1516/1590] Cool, doesn't need six any more --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index bfa2ac7a9..a3656273c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -35,7 +35,6 @@ install_requires = Django>=3.2 Pillow>=2.0.0 django-mptt>=0.7.1 - six python_requires = >=3.6 include_package_data = True zip_safe = False From 8c2d84111b400ce03a61279058559214c8c30809 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 16 Mar 2022 08:19:12 +0100 Subject: [PATCH 1517/1590] Update our pre-commit hooks and fix a few JS problems with global vars --- .eslintrc.js | 19 ++- .gitignore | 16 +-- .pre-commit-config.yaml | 36 +++--- feincms/contrib/tagging.py | 3 +- feincms/management/commands/rebuild_mptt.py | 1 + feincms/module/medialibrary/modeladmins.py | 13 +- feincms/static/feincms/item_editor.js | 120 ++++++++---------- feincms/static/feincms/js.cookie.js | 36 +++--- feincms/static/feincms/tree_editor.js | 132 ++++++++++---------- 9 files changed, 184 insertions(+), 192 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3514ca2af..63570efc3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,5 @@ module.exports = { + parser: "@babel/eslint-parser", env: { browser: true, es6: true, @@ -6,11 +7,21 @@ module.exports = { }, extends: ["eslint:recommended", "prettier"], parserOptions: { - ecmaVersion: 2018, + ecmaFeatures: { + experimentalObjectRestSpread: true, + jsx: true, + }, + ecmaVersion: 2021, + requireConfigFile: false, + sourceType: "module", }, rules: { - "linebreak-style": ["error", "unix"], - "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], - quotes: 0, + "no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], }, } diff --git a/.gitignore b/.gitignore index 4cdbee3c0..c02765c74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,23 @@ *.pyc *~ .*.swp -\#*# -/secrets.py .DS_Store ._* +.coverage +.tox /FeinCMS.egg-info /MANIFEST /_build /build /dist -tests/test.zip /docs/_build -/tests/.tox +/secrets.py /tests/.coverage +/tests/.tox /tests/htmlcov -venv -.tox -.coverage +\#*# htmlcov -test.zip node_modules +test.zip +tests/test.zip +venv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f133eb11..53bf112eb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -exclude: ".yarn/|yarn.lock|\\.min\\.(css|js)$" +exclude: ".yarn/|yarn.lock|.min.js$" repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.1.0 @@ -7,11 +7,15 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - id: trailing-whitespace + - id: file-contents-sorter + files: requirements-to-freeze.txt + - id: file-contents-sorter + files: .gitignore - repo: https://github.com/asottile/pyupgrade - rev: v2.29.1 + rev: v2.31.1 hooks: - id: pyupgrade - args: [--py39-plus] + args: [--py36-plus] - repo: https://github.com/adamchainz/django-upgrade rev: 1.4.0 hooks: @@ -23,7 +27,7 @@ repos: - id: isort args: [--profile=black, --lines-after-imports=2, --combine-as] - repo: https://github.com/psf/black - rev: 21.12b0 + rev: 22.3.0 hooks: - id: black - repo: https://github.com/pycqa/flake8 @@ -31,17 +35,21 @@ repos: hooks: - id: flake8 args: ["--ignore=E203,E501,W503"] - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.5.1 - hooks: - - id: prettier - args: [--list-different, --no-semi] - exclude: "\\.html$" - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.6.0 + rev: v8.12.0 hooks: - id: eslint + args: [--fix] + verbose: true additional_dependencies: - - eslint@8.6.0 - - eslint-config-prettier@8.3.0 - exclude: "js.cookie.js|\\.min\\.js$" + - eslint@8.12.0 + - eslint-config-prettier@8.5.0 + - "@babel/core" + - "@babel/eslint-parser" + - "@babel/preset-env" + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.6.1 + hooks: + - id: prettier + args: [--list-different, --no-semi] + exclude: "^conf/|.*\\.html$|.*\\.json$" diff --git a/feincms/contrib/tagging.py b/feincms/contrib/tagging.py index f1b5c767a..6c29eb727 100644 --- a/feincms/contrib/tagging.py +++ b/feincms/contrib/tagging.py @@ -12,11 +12,10 @@ from django.contrib.admin.widgets import FilteredSelectMultiple from django.db.models.signals import pre_save from django.utils.translation import gettext_lazy as _ - from tagging.fields import TagField from tagging.models import Tag -from tagging.utils import parse_tag_input from tagging.registry import AlreadyRegistered, register as tagging_register +from tagging.utils import parse_tag_input # ------------------------------------------------------------------------ diff --git a/feincms/management/commands/rebuild_mptt.py b/feincms/management/commands/rebuild_mptt.py index df52c1ae7..e20332f39 100644 --- a/feincms/management/commands/rebuild_mptt.py +++ b/feincms/management/commands/rebuild_mptt.py @@ -9,6 +9,7 @@ from django.core.management.base import BaseCommand + from feincms.module.page.models import Page diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 40639a4bc..2b3feb790 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -55,14 +55,11 @@ class AddCategoryForm(forms.Form): category.mediafile_set.add(mediafile) count += 1 - message = ( - ngettext( - "Successfully added %(count)d media file to %(category)s.", - "Successfully added %(count)d media files to %(category)s.", - count, - ) - % {"count": count, "category": category} - ) + message = ngettext( + "Successfully added %(count)d media file to %(category)s.", + "Successfully added %(count)d media files to %(category)s.", + count, + ) % {"count": count, "category": category} modeladmin.message_user(request, message) return HttpResponseRedirect(request.get_full_path()) if "cancel" in request.POST: diff --git a/feincms/static/feincms/item_editor.js b/feincms/static/feincms/item_editor.js index f531d12fa..40fb88edf 100644 --- a/feincms/static/feincms/item_editor.js +++ b/feincms/static/feincms/item_editor.js @@ -1,4 +1,4 @@ -/* global Downcoder, django, feincms */ +/* global Downcoder, django, feincms, ItemEditor, interpolate */ /* global IMG_DELETELINK_PATH, REGION_MAP, REGION_NAMES, ACTIVE_REGION, CONTENT_NAMES, FEINCMS_ITEM_EDITOR_GETTEXT, CONTENT_TYPE_BUTTONS */ /* global contentblock_init_handlers, contentblock_move_handlers */ /* global id_to_windowname */ @@ -35,19 +35,17 @@ if (!Array.prototype.indexOf) { function create_new_item_from_form(form, modname, modvar) { let fieldset = $("
").addClass( - "module aligned order-item item-wrapper-" + modvar + `module aligned order-item item-wrapper-${modvar}` ) - let original_id_id = "#id_" + form.attr("id") + "-id" + let original_id_id = `#id_${form.attr("id")}-id` let wrp = ["

"] // If original has delete checkbox or this is a freshly added CT? Add delete link! if ($(".delete", form).length || !$(original_id_id, form).val()) { - wrp.push('') + wrp.push(``) } wrp.push( - ' ' + - modname + - "

" + ` ${modname}` ) wrp.push('
') fieldset.append(wrp.join("")) @@ -79,7 +77,7 @@ if (!Array.prototype.indexOf) { let insert_control = $("
").addClass("item-control-unit") let select_content = SELECTS[REGION_MAP[target_region_id]].clone() - select_content.change(function () { + select_content.change(() => { let modvar = select_content.val() let modname = select_content.find("option:selected").html() let new_fieldset = create_new_fieldset_from_module(modvar, modname) @@ -102,20 +100,16 @@ if (!Array.prototype.indexOf) { '
' + '
' + '', ) /* Simulate a click on the save button instead of form.submit(), so that the submit handlers from FilteredSelectMultiple get @@ -574,7 +574,7 @@ if (!Array.prototype.indexOf) { if (!elem.hasClass("empty-form")) { let region_id = REGION_MAP.indexOf( - elem.find(".region-choice-field").val() + elem.find(".region-choice-field").val(), ) if (REGION_MAP[region_id] != undefined) { let content_type = elem @@ -583,7 +583,7 @@ if (!Array.prototype.indexOf) { let item = create_new_item_from_form( elem, CONTENT_NAMES[content_type], - content_type + content_type, ) add_fieldset(region_id, item, { where: "append" }) update_item_controls(item, region_id) @@ -655,7 +655,7 @@ if (!Array.prototype.indexOf) { add_content(type, region) { let new_fieldset = create_new_fieldset_from_module( type, - CONTENT_NAMES[type] + CONTENT_NAMES[type], ) add_fieldset(region, new_fieldset, { where: "append", animate: "true" }) update_item_controls(new_fieldset, region) diff --git a/feincms/static/feincms/tree_editor.js b/feincms/static/feincms/tree_editor.js index 2918dfc57..8f69c9c6e 100755 --- a/feincms/static/feincms/tree_editor.js +++ b/feincms/static/feincms/tree_editor.js @@ -162,7 +162,7 @@ feincms.jQuery(($) => { // check if drag_line element already exists, else append if ($("#drag_line").length < 1) { $("body").append( - '
line
' + '
line
', ) } @@ -246,10 +246,10 @@ feincms.jQuery(($) => { $("body").bind("mouseup", () => { if (moveTo.relativeTo) { let cutItem = extractItemId( - originalRow.find(".page_marker").attr("id") + originalRow.find(".page_marker").attr("id"), ) let pastedOn = extractItemId( - moveTo.relativeTo.find(".page_marker").attr("id") + moveTo.relativeTo.find(".page_marker").attr("id"), ) // get out early if items are the same if (cutItem != pastedOn) { @@ -278,7 +278,7 @@ feincms.jQuery(($) => { }, () => { window.location.reload() - } + }, ) } else { $("#drag_line").remove() @@ -294,7 +294,7 @@ feincms.jQuery(($) => { }) return this - }) + }), ) /* Every time the user expands or collapses a part of the tree, we remember @@ -353,7 +353,7 @@ feincms.jQuery(($) => { rlist.show() }) return this - }) + }), ) // bind the open all children event @@ -375,7 +375,7 @@ feincms.jQuery(($) => { rlist.show() }) return this - }) + }), ) let changelist_tab = function (elem, event, direction) { diff --git a/feincms/urls.py b/feincms/urls.py index 1094fd6d8..da949533a 100644 --- a/feincms/urls.py +++ b/feincms/urls.py @@ -1,4 +1,4 @@ -from django.urls import re_path +from django.urls import path, re_path from feincms.views import Handler @@ -6,6 +6,6 @@ handler = Handler.as_view() urlpatterns = [ - re_path(r"^$", handler, name="feincms_home"), + path("", handler, name="feincms_home"), re_path(r"^(.*)/$", handler, name="feincms_handler"), ] diff --git a/tests/testapp/applicationcontent_urls.py b/tests/testapp/applicationcontent_urls.py index de3b9ac3e..a250de912 100644 --- a/tests/testapp/applicationcontent_urls.py +++ b/tests/testapp/applicationcontent_urls.py @@ -6,7 +6,7 @@ from django.http import HttpResponse, HttpResponseRedirect from django.template.loader import render_to_string from django.template.response import TemplateResponse -from django.urls import re_path +from django.urls import path, re_path from feincms.content.application.models import standalone, unpack @@ -51,15 +51,15 @@ def inheritance20_unpack(request): urlpatterns = [ - re_path(r"^$", module_root, name="ac_module_root"), + path("", module_root, name="ac_module_root"), re_path(r"^args_test/([^/]+)/([^/]+)/$", args_test, name="ac_args_test"), - re_path(r"^kwargs_test/(?P[^/]+)/(?P[^/]+)/$", args_test), - re_path(r"^full_reverse_test/$", full_reverse_test), - re_path(r"^alias_reverse_test/$", alias_reverse_test), - re_path(r"^fragment/$", fragment), - re_path(r"^redirect/$", redirect), - re_path(r"^response/$", response), - re_path(r"^response_decorated/$", standalone(response)), - re_path(r"^inheritance20/$", inheritance20), - re_path(r"^inheritance20_unpack/$", inheritance20_unpack), + path("kwargs_test///", args_test), + path("full_reverse_test/", full_reverse_test), + path("alias_reverse_test/", alias_reverse_test), + path("fragment/", fragment), + path("redirect/", redirect), + path("response/", response), + path("response_decorated/", standalone(response)), + path("inheritance20/", inheritance20), + path("inheritance20_unpack/", inheritance20_unpack), ] diff --git a/tests/testapp/migrate/medialibrary/0001_initial.py b/tests/testapp/migrate/medialibrary/0001_initial.py index 32254cbd6..d01111132 100644 --- a/tests/testapp/migrate/medialibrary/0001_initial.py +++ b/tests/testapp/migrate/medialibrary/0001_initial.py @@ -9,7 +9,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [] diff --git a/tests/testapp/migrate/page/0001_initial.py b/tests/testapp/migrate/page/0001_initial.py index 77e21c352..64148bc38 100644 --- a/tests/testapp/migrate/page/0001_initial.py +++ b/tests/testapp/migrate/page/0001_initial.py @@ -11,7 +11,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/testapp/migrations/0001_initial.py b/tests/testapp/migrations/0001_initial.py index 2eb868768..7a4377a0d 100644 --- a/tests/testapp/migrations/0001_initial.py +++ b/tests/testapp/migrations/0001_initial.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [] diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index db13f80d1..c249aebba 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.contrib.sitemaps.views import sitemap from django.contrib.staticfiles.urls import staticfiles_urlpatterns -from django.urls import include, re_path +from django.urls import include, path, re_path from django.views.static import serve from feincms.module.page.sitemap import PageSitemap @@ -21,8 +21,8 @@ {"document_root": os.path.join(os.path.dirname(__file__), "media/")}, ), re_path(r"^sitemap\.xml$", sitemap, {"sitemaps": sitemaps}), - re_path(r"", include("feincms.contrib.preview.urls")), - re_path(r"", include("feincms.urls")), + path("", include("feincms.contrib.preview.urls")), + path("", include("feincms.urls")), ] urlpatterns += staticfiles_urlpatterns() From f0339a4f9227b8f714e805f35151c2dec28e4f11 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 9 Mar 2023 10:48:55 +0100 Subject: [PATCH 1533/1590] Update the CI matrix --- tox.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index d05bba62f..be29261a1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] envlist = - py{38,39,310}-dj{32,40,main} + py{38,39,310}-dj{32,41,42} + py{310}-dj{32,41,42,main} [testenv] usedevelop = true @@ -10,5 +11,6 @@ commands = coverage report -m deps = dj32: Django>=3.2,<4.0 - dj40: Django>=4.0,<4.1 + dj41: Django>=4.1,<4.2 + dj42: Django>=4.2a1,<5.0 djmain: https://github.com/django/django/archive/main.tar.gz From 2067bdd5cd0f2bae8518b52d861e0cadbd17eb6a Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 9 Mar 2023 10:55:05 +0100 Subject: [PATCH 1534/1590] Remove the deprecated and removed is_dst argument to make_aware --- CHANGELOG.rst | 5 +++++ feincms/extensions/datepublisher.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e6f2da040..a249b22f0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,11 @@ Change log .. _Next version: https://github.com/feincms/feincms/compare/v22.4.0...main +- Fixed a place where ``ACTION_CHECKBOX_NAME`` was imported from the wrong + place. +- Dropped the ``is_dst`` argument to ``timezone.make_aware``. +- Added Django 4.1 and 4.2 to the CI matrix. + `v22.4.0`_ (2022-06-02) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index d458b89d7..49111ed59 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -56,7 +56,7 @@ def granular_now(n=None, default_tz=None): rounded_minute = (n.minute // 5) * 5 d = datetime(n.year, n.month, n.day, n.hour, rounded_minute) - return timezone.make_aware(d, default_tz, is_dst=True) + return timezone.make_aware(d, default_tz) # ------------------------------------------------------------------------ From cb0969cd5296e2cb3f6e11f66ec8a348361bfa6e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 9 Mar 2023 11:08:50 +0100 Subject: [PATCH 1535/1590] Keep is_dst around for older Django versions --- feincms/extensions/datepublisher.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feincms/extensions/datepublisher.py b/feincms/extensions/datepublisher.py index 49111ed59..1c99fb9f6 100644 --- a/feincms/extensions/datepublisher.py +++ b/feincms/extensions/datepublisher.py @@ -11,6 +11,7 @@ from datetime import datetime +import django from django.db import models from django.db.models import Q from django.utils import timezone @@ -56,7 +57,10 @@ def granular_now(n=None, default_tz=None): rounded_minute = (n.minute // 5) * 5 d = datetime(n.year, n.month, n.day, n.hour, rounded_minute) - return timezone.make_aware(d, default_tz) + if django.VERSION < (5,): + return timezone.make_aware(d, default_tz, is_dst=True) + else: + return timezone.make_aware(d, default_tz) # ------------------------------------------------------------------------ From 8e3a0cbc28db488f963d37beec59db83bc3ee2da Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 9 Mar 2023 11:11:59 +0100 Subject: [PATCH 1536/1590] Update the GitHub actions version --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4551158f6..a4c30d22e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,9 +19,9 @@ jobs: - "3.10" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 3f254320e2c41945b01d29b029c1d296b3e74abe Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 9 Mar 2023 11:13:25 +0100 Subject: [PATCH 1537/1590] FeinCMS v23.1.0 --- CHANGELOG.rst | 8 +++++++- feincms/__init__.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a249b22f0..e67fbd74d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,13 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ -.. _Next version: https://github.com/feincms/feincms/compare/v22.4.0...main +.. _Next version: https://github.com/feincms/feincms/compare/v23.1.0...main + + +`v23.1.0`_ (2023-03-09) +~~~~~~~~~~~~~~~~~~~~~~~ + +.. _v23.1.0: https://github.com/feincms/feincms/compare/v22.4.0...v23.1.0 - Fixed a place where ``ACTION_CHECKBOX_NAME`` was imported from the wrong place. diff --git a/feincms/__init__.py b/feincms/__init__.py index e1ef4b92f..dbff7b49d 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (22, 4, 0) +VERSION = (23, 1, 0) __version__ = ".".join(map(str, VERSION)) From a64d249f30c562968fc4df1902178accd11aa53d Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 20 Jul 2023 13:22:33 +0200 Subject: [PATCH 1538/1590] ApplicationContent should pass cookies to final response. Issue #706 --- feincms/content/application/models.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/feincms/content/application/models.py b/feincms/content/application/models.py index 3c154c3c7..2ce30cf74 100644 --- a/feincms/content/application/models.py +++ b/feincms/content/application/models.py @@ -354,6 +354,10 @@ def process(self, request, **kw): if h in output: self.rendered_headers.setdefault(h, []).append(output[h]) + application_cookies = output.cookies + if application_cookies: + self.rendered_headers['X-Feincms-Cookie'] = application_cookies + elif isinstance(output, tuple) and "view" in kw: kw["view"].template_name = output[0] kw["view"].request._feincms_extra_context.update(output[1]) @@ -420,6 +424,15 @@ def _update_response_headers(self, request, response, headers): if len(lm_list) > 0: response["Expires"] = http_date(mktime(min(lm_list))) + # Add all cookies + cookies = headers.get('X-Feincms-Cookie', None) + if cookies: + for kookie, val in cookies.items(): + response.set_cookie(kookie, value=val.value, + max_age=val['max-age'], expires=val['expires'], path=val['path'], + domain=val['domain'], secure=val['secure'], httponly=val['httponly'], + samesite=val['samesite']) + @classmethod def app_reverse_cache_key(self, urlconf_path, **kwargs): return "FEINCMS:{}:APPCONTENT:{}:{}".format( From cbc29c3da8a3e3b88a6601b6ddbaa8ef80c0159c Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 20 Jul 2023 13:28:11 +0200 Subject: [PATCH 1539/1590] Newer PILs do not have PIL.Image.ANTIALIAS any more. Use .LANCZOS instead. --- feincms/templatetags/feincms_thumbnail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 2c774406b..de4cd9a28 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -122,7 +122,7 @@ def generate(self, storage, original, size, miniature): w, h = int(size["w"]), int(size["h"]) format = image.format # Save format for the save() call later - image.thumbnail([w, h], Image.ANTIALIAS) + image.thumbnail([w, h], Image.LANCZOS) buf = BytesIO() if format.lower() not in ("jpg", "jpeg", "png"): format = "jpeg" @@ -182,7 +182,7 @@ def generate(self, storage, original, size, miniature): y_offset + int(crop_height), ) ) - image = image.resize((dst_width, dst_height), Image.ANTIALIAS) + image = image.resize((dst_width, dst_height), Image.LANCZOS) buf = BytesIO() if format.lower() not in ("jpg", "jpeg", "png"): From e3b032b2b441934740f746a1342b473cae19d2c0 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 7 Aug 2023 07:50:55 +0200 Subject: [PATCH 1540/1590] Improve interoperability --- .pre-commit-config.yaml | 12 ++++++------ CHANGELOG.rst | 4 ++++ feincms/models.py | 9 ++++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 625b2cd6b..e27f3c582 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,12 +12,12 @@ repos: - id: file-contents-sorter files: .gitignore - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.10.1 hooks: - id: pyupgrade args: [--py38-plus] - repo: https://github.com/adamchainz/django-upgrade - rev: 1.13.0 + rev: 1.14.0 hooks: - id: django-upgrade args: [--target-version, "3.2"] @@ -27,16 +27,16 @@ repos: - id: isort args: [--profile=black, --lines-after-imports=2, --combine-as] - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.7.0 hooks: - id: black - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 args: ["--ignore=E203,E501,W503"] - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.35.0 + rev: v8.46.0 hooks: - id: eslint args: [--fix] @@ -48,7 +48,7 @@ repos: - "@babel/eslint-parser" - "@babel/preset-env" - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.0-alpha.6 + rev: v3.0.1 hooks: - id: prettier args: [--list-different, --no-semi] diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e67fbd74d..bf0019017 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,10 @@ Change log .. _Next version: https://github.com/feincms/feincms/compare/v23.1.0...main +- Made the filter argument of content base's ``get_queryset`` method optional. + This enables easier interoperability of FeinCMS content types with feincms3 + plugins. + `v23.1.0`_ (2023-03-09) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/feincms/models.py b/feincms/models.py index be587ed5b..bb8abeba9 100644 --- a/feincms/models.py +++ b/feincms/models.py @@ -210,7 +210,7 @@ def _populate_content_type_caches(self, types): if cls not in self._cache["cts"]: if counts: self._cache["cts"][cls] = list( - cls.get_queryset( + cls.get_queryset().filter( reduce( operator.or_, (Q(region=r[0], parent=r[1]) for r in counts), @@ -500,8 +500,11 @@ def render(self, **kwargs): raise NotImplementedError - def get_queryset(cls, filter_args): - return cls.objects.select_related().filter(filter_args) + def get_queryset(cls, filter_args=None): + qs = cls.objects.select_related() + if filter_args is not None: + return qs.filter(filter_args) + return qs attrs = { # The basic content type is put into From 2b9ffbecc908e2003371bb29e6ecce88e5ea1bbd Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 7 Aug 2023 07:55:56 +0200 Subject: [PATCH 1541/1590] Add Python 3.11 --- .github/workflows/tests.yml | 1 + CHANGELOG.rst | 1 + tox.ini | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a4c30d22e..cd0c5da4d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,6 +17,7 @@ jobs: - "3.8" - "3.9" - "3.10" + - "3.11" steps: - uses: actions/checkout@v3 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bf0019017..4868abc84 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ Change log - Made the filter argument of content base's ``get_queryset`` method optional. This enables easier interoperability of FeinCMS content types with feincms3 plugins. +- Added Python 3.11. `v23.1.0`_ (2023-03-09) diff --git a/tox.ini b/tox.ini index be29261a1..3fd4055b3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = py{38,39,310}-dj{32,41,42} - py{310}-dj{32,41,42,main} + py{310,311}-dj{32,41,42,main} [testenv] usedevelop = true @@ -12,5 +12,5 @@ commands = deps = dj32: Django>=3.2,<4.0 dj41: Django>=4.1,<4.2 - dj42: Django>=4.2a1,<5.0 + dj42: Django>=4.2,<5.0 djmain: https://github.com/django/django/archive/main.tar.gz From c64fcdb3028351ea3e61a67406fff466e256c3ce Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 7 Aug 2023 08:24:20 +0200 Subject: [PATCH 1542/1590] It's Image.Resampling.* now --- CHANGELOG.rst | 1 + feincms/templatetags/feincms_thumbnail.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4868abc84..efbf1190d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,7 @@ Change log This enables easier interoperability of FeinCMS content types with feincms3 plugins. - Added Python 3.11. +- Fixed the Pillow resampling constant. `v23.1.0`_ (2023-03-09) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 2c774406b..9f1b9d5dc 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -122,7 +122,7 @@ def generate(self, storage, original, size, miniature): w, h = int(size["w"]), int(size["h"]) format = image.format # Save format for the save() call later - image.thumbnail([w, h], Image.ANTIALIAS) + image.thumbnail([w, h], Image.Resampling.LANCZOS) buf = BytesIO() if format.lower() not in ("jpg", "jpeg", "png"): format = "jpeg" @@ -182,7 +182,7 @@ def generate(self, storage, original, size, miniature): y_offset + int(crop_height), ) ) - image = image.resize((dst_width, dst_height), Image.ANTIALIAS) + image = image.resize((dst_width, dst_height), Image.Resampling.LANCZOS) buf = BytesIO() if format.lower() not in ("jpg", "jpeg", "png"): From ec455aa9067b9f211f271a12e27dc4631d056a5e Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 7 Aug 2023 08:30:00 +0200 Subject: [PATCH 1543/1590] FeinCMS v23.8.0 --- CHANGELOG.rst | 8 +++++++- feincms/__init__.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index efbf1190d..74a5dc1b5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,13 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ -.. _Next version: https://github.com/feincms/feincms/compare/v23.1.0...main +.. _Next version: https://github.com/feincms/feincms/compare/v23.8.0...main + + +`v23.8.0`_ (2023-08-07) +~~~~~~~~~~~~~~~~~~~~~~~ + +.. _v23.8.0: https://github.com/feincms/feincms/compare/v23.1.0...v23.8.0 - Made the filter argument of content base's ``get_queryset`` method optional. This enables easier interoperability of FeinCMS content types with feincms3 diff --git a/feincms/__init__.py b/feincms/__init__.py index dbff7b49d..b3462a34f 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (23, 1, 0) +VERSION = (23, 8, 0) __version__ = ".".join(map(str, VERSION)) From aacde745f78f2a88e023ad7a4560136d2722bd5e Mon Sep 17 00:00:00 2001 From: Jeroen Pulles Date: Fri, 22 Dec 2023 14:39:56 +0100 Subject: [PATCH 1544/1590] Close image after reading dimensions. (#709) The mediafile admin page triggers a ResourceWarning; The warning you get to see after viewing a mediafile webpage is:: ResourceWarning: unclosed file <_io.BufferedReader name='/***/helloworld.png'> ResourceWarning: Enable tracemalloc to get the object allocation traceback Django's get_image_dimensions() leaves the file open unless you call close=True; Alternatively the admin code could do add a finally clause to the try/except and do a obj.file.close() there. But this change seems to be in the spirit of get_image_dimensions(). Co-authored-by: Jeroen Pulles --- feincms/module/medialibrary/modeladmins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/module/medialibrary/modeladmins.py b/feincms/module/medialibrary/modeladmins.py index 64fe8db7e..721b97c04 100644 --- a/feincms/module/medialibrary/modeladmins.py +++ b/feincms/module/medialibrary/modeladmins.py @@ -169,7 +169,7 @@ def file_type(self, obj): except NotImplementedError: return t try: - d = get_image_dimensions(obj.file.file) + d = get_image_dimensions(obj.file.file, close=True) if d: t += " %d×%d" % (d[0], d[1]) except (OSError, TypeError, ValueError) as e: From aa3844a76e47957292be041c523f6d4930d80893 Mon Sep 17 00:00:00 2001 From: Jeroen Pulles Date: Fri, 22 Dec 2023 14:40:09 +0100 Subject: [PATCH 1545/1590] Log exceptions at the exception level, instead of warning. (#708) It took me a while to notice that a Pillow upgrade went bad; If this was an exception level log statement I would have been alerted in my log watches. Co-authored-by: Jeroen Pulles --- feincms/templatetags/feincms_thumbnail.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index 9f1b9d5dc..01fa469e6 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -97,12 +97,7 @@ def __str__(self): miniature=miniature, ) except Exception as exc: - logger.warning( - "Rendering a thumbnail failed: %r", - exc, - exc_info=True, - extra={"stack": True, "exception": exc}, - ) + logger.exception("Rendering a thumbnail failed: %s", exc) # PIL raises a plethora of Exceptions if reading the image # is not possible. Since we cannot be sure what Exception will # happen, catch them all so the thumbnailer will never fail. From 44a84b90f645645e0b43e598ac6c131e9f99fc07 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 22 Dec 2023 14:52:16 +0100 Subject: [PATCH 1546/1590] Add Python 3.12, Django 5.0 (#710) --- .github/workflows/tests.yml | 1 + setup.cfg | 4 ++-- tox.ini | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cd0c5da4d..b0c9a3595 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,6 +18,7 @@ jobs: - "3.9" - "3.10" - "3.11" + - "3.12" steps: - uses: actions/checkout@v3 diff --git a/setup.cfg b/setup.cfg index a3656273c..bdee4d2e8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -19,11 +19,11 @@ classifiers = Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 Programming Language :: Python :: Implementation :: CPython Topic :: Internet :: WWW/HTTP :: Dynamic Content Topic :: Software Development diff --git a/tox.ini b/tox.ini index 3fd4055b3..bc00879a2 100644 --- a/tox.ini +++ b/tox.ini @@ -2,6 +2,7 @@ envlist = py{38,39,310}-dj{32,41,42} py{310,311}-dj{32,41,42,main} + py{312}-dj{42,50,main} [testenv] usedevelop = true @@ -13,4 +14,5 @@ deps = dj32: Django>=3.2,<4.0 dj41: Django>=4.1,<4.2 dj42: Django>=4.2,<5.0 + dj50: Django>=5.0,<5.1 djmain: https://github.com/django/django/archive/main.tar.gz From ce68bdd371b6bb38005ce3b78c7969d317174f13 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 22 Dec 2023 14:54:05 +0100 Subject: [PATCH 1547/1590] FeinCMS v23.12.0 --- CHANGELOG.rst | 8 +++++++- feincms/__init__.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 74a5dc1b5..c7bde06d2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,13 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ -.. _Next version: https://github.com/feincms/feincms/compare/v23.8.0...main +v23.12.0 (2023-12-22) +~~~~~~~~~~~~~~~~~~~~~ + +- Added Python 3.12, Django 5.0. +- Closed images after reading their dimensions. Raised the logging level to + exception when thumbnailing fails. Thanks to Jeroen Pulles for those two + contributions! `v23.8.0`_ (2023-08-07) diff --git a/feincms/__init__.py b/feincms/__init__.py index b3462a34f..944fd8ded 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (23, 8, 0) +VERSION = (23, 12, 0) __version__ = ".".join(map(str, VERSION)) From 3e497e4f094f618c86d4d54830486f2538b2c076 Mon Sep 17 00:00:00 2001 From: Samuel Lim Date: Mon, 8 Apr 2024 16:04:33 +0200 Subject: [PATCH 1548/1590] Use csrftoken on webpage instead of cookie. This allows the setting CSRF_HTTP_ONLY = True. (#711) Co-authored-by: Samuel Lim --- feincms/static/feincms/tree_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/static/feincms/tree_editor.js b/feincms/static/feincms/tree_editor.js index 8f69c9c6e..e97731728 100755 --- a/feincms/static/feincms/tree_editor.js +++ b/feincms/static/feincms/tree_editor.js @@ -9,7 +9,7 @@ feincms.jQuery.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend(xhr, settings) { if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)) { - xhr.setRequestHeader("X-CSRFToken", Cookies.get("csrftoken")) + xhr.setRequestHeader("X-CSRFToken", document.querySelector('input[name="csrfmiddlewaretoken"]').value); } }, }) From 962cc014c0eaab44903f7c649b364bd3bb9f8bc3 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 8 Apr 2024 16:06:13 +0200 Subject: [PATCH 1549/1590] FeinCMS v24.4.0 --- CHANGELOG.rst | 8 ++++++++ feincms/__init__.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c7bde06d2..27a689000 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,14 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ +v24.4.0 (2024-04-08) +~~~~~~~~~~~~~~~~~~~~~ + +- Fetched the CSRF token value from the input field instead of from the cookie. + This allows making the CSRF cookie ``httponly``. Thanks to Samuel Lin for the + contribution! + + v23.12.0 (2023-12-22) ~~~~~~~~~~~~~~~~~~~~~ diff --git a/feincms/__init__.py b/feincms/__init__.py index 944fd8ded..8edbdbb1a 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (23, 12, 0) +VERSION = (24, 4, 0) __version__ = ".".join(map(str, VERSION)) From f3b91724371dccf126cdda6adb93778ac52e9483 Mon Sep 17 00:00:00 2001 From: Samuel Lim Date: Tue, 9 Apr 2024 10:06:59 +0200 Subject: [PATCH 1550/1590] Small typo in my family name (#712) --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 27a689000..1f7d1217d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,7 +10,7 @@ v24.4.0 (2024-04-08) ~~~~~~~~~~~~~~~~~~~~~ - Fetched the CSRF token value from the input field instead of from the cookie. - This allows making the CSRF cookie ``httponly``. Thanks to Samuel Lin for the + This allows making the CSRF cookie ``httponly``. Thanks to Samuel Lim for the contribution! From 14e655f11a497ed8001fb7d15a274fe10f6619b9 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Mon, 15 Apr 2024 11:03:35 +0200 Subject: [PATCH 1551/1590] Support webp as image format (medialibrary recognizes it as image, admin can show thumbnail). Minor refactoring, still lots of duplicated code here! --- feincms/module/medialibrary/models.py | 2 +- feincms/templatetags/feincms_thumbnail.py | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/feincms/module/medialibrary/models.py b/feincms/module/medialibrary/models.py index 0931bb4a2..056eb2852 100644 --- a/feincms/module/medialibrary/models.py +++ b/feincms/module/medialibrary/models.py @@ -228,7 +228,7 @@ def delete_mediafile(self, name=None): "image", _("Image"), lambda f: re.compile( - r"\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?)$", re.IGNORECASE + r"\.(bmp|jpe?g|jp2|jxr|gif|png|tiff?|webp)$", re.IGNORECASE ).search(f), ), ( diff --git a/feincms/templatetags/feincms_thumbnail.py b/feincms/templatetags/feincms_thumbnail.py index c284392a6..3bfa02861 100644 --- a/feincms/templatetags/feincms_thumbnail.py +++ b/feincms/templatetags/feincms_thumbnail.py @@ -23,6 +23,8 @@ class Thumbnailer: THUMBNAIL_SIZE_RE = re.compile(r"^(?P\d+)x(?P\d+)$") MARKER = "_thumb_" + BROWSER_SUPPORTED_FORMATS = ("jpg", "jpeg", "png", "webp") # browser supported image formats + TRANSPARENCY_SUPPORTING_FORMATS = ('png', 'webp') # formats with alpha channel def __init__(self, filename, size="200x200"): self.filename = filename @@ -85,7 +87,7 @@ def __str__(self): # storage does NOT support modified_time generate = False except OSError: - # Someone might have delete the file + # Someone might have deleted the file return "" if generate: @@ -116,13 +118,14 @@ def generate(self, storage, original, size, miniature): # defining the size w, h = int(size["w"]), int(size["h"]) - format = image.format # Save format for the save() call later - image.thumbnail([w, h], Image.LANCZOS) + assert image.format is not None + format = image.format.lower() # Save format for the save() call later + image.thumbnail([w, h], Image.Resampling.LANCZOS) buf = BytesIO() - if format.lower() not in ("jpg", "jpeg", "png"): + if format not in self.BROWSER_SUPPORTED_FORMATS: # browser supported image formats format = "jpeg" if image.mode not in ("RGBA", "RGB", "L"): - if format == "png": + if format in self.TRANSPARENCY_SUPPORTING_FORMATS: # handles transparency? image = image.convert("RGBA") else: image = image.convert("RGB") @@ -168,7 +171,8 @@ def generate(self, storage, original, size, miniature): x_offset = 0 y_offset = int(float(src_height - crop_height) * y / 100) - format = image.format # Save format for the save() call later + assert image.format is not None + format = image.format.lower() # Save format for the save() call later image = image.crop( ( x_offset, @@ -177,13 +181,13 @@ def generate(self, storage, original, size, miniature): y_offset + int(crop_height), ) ) - image = image.resize((dst_width, dst_height), Image.LANCZOS) + image = image.resize((dst_width, dst_height), Image.Resampling.LANCZOS) buf = BytesIO() - if format.lower() not in ("jpg", "jpeg", "png"): + if format not in self.BROWSER_SUPPORTED_FORMATS: format = "jpeg" if image.mode not in ("RGBA", "RGB", "L"): - if format == "png": + if format in self.TRANSPARENCY_SUPPORTING_FORMATS: image = image.convert("RGBA") else: image = image.convert("RGB") From 28a60def548e4c92a36b5ab762166dea28311e57 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Tue, 16 Apr 2024 10:17:25 +0200 Subject: [PATCH 1552/1590] FeinCMS v24.4.1 --- CHANGELOG.rst | 8 ++++++++ feincms/__init__.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1f7d1217d..e40d01e10 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,14 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ + +v24.4.1 (2024-04-16) +~~~~~~~~~~~~~~~~~~~~~ + +- Forwarded cookies set by ``ApplicationContent`` apps to the final response. +- Added support for webp image formats to the media library. + + v24.4.0 (2024-04-08) ~~~~~~~~~~~~~~~~~~~~~ diff --git a/feincms/__init__.py b/feincms/__init__.py index 8edbdbb1a..368aeeee6 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (24, 4, 0) +VERSION = (24, 4, 1) __version__ = ".".join(map(str, VERSION)) From e0079bf04bda0450cf7b2f9ed2f1f37a6c517623 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 18 Apr 2024 09:38:50 +0200 Subject: [PATCH 1553/1590] Update admin CategoryFieldListFilter and ParentFieldListFilter to work with Django 5, which now allows multi-selections in admin filters. Rename parameters to match parent class' parameter names --- feincms/admin/filters.py | 45 ++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/feincms/admin/filters.py b/feincms/admin/filters.py index dc77ce9ab..7ae5bdc5a 100644 --- a/feincms/admin/filters.py +++ b/feincms/admin/filters.py @@ -4,6 +4,9 @@ # Guilherme M. Gondim (semente) +from operator import itemgetter + +import django from django.contrib.admin.filters import ChoicesFieldListFilter from django.db.models import Count from django.utils.encoding import smart_str @@ -23,8 +26,8 @@ class ParentFieldListFilter(ChoicesFieldListFilter): my_model_field.page_parent_filter = True """ - def __init__(self, f, request, params, model, model_admin, field_path=None): - super().__init__(f, request, params, model, model_admin, field_path) + def __init__(self, field, request, params, model, model_admin, field_path=None): + super().__init__(field, request, params, model, model_admin, field_path) parent_ids = ( model.objects.exclude(parent=None) @@ -45,17 +48,23 @@ def __init__(self, f, request, params, model, model_admin, field_path=None): for pk, title, level in parents ] - def choices(self, cl): + def choices(self, changelist): yield { "selected": self.lookup_val is None, - "query_string": cl.get_query_string({}, [self.lookup_kwarg]), + "query_string": changelist.get_query_string({}, [self.lookup_kwarg]), "display": _("All"), } + # Pre Django 5 lookup_val would be a scalar, now it can do multiple + # selections and thus is a list. Deal with that. + lookup_vals = self.lookup_val + if lookup_vals is not None and django.VERSION < (5,): + lookup_vals = [lookup_vals] + for pk, title in self.lookup_choices: yield { - "selected": pk == int(self.lookup_val or "0"), - "query_string": cl.get_query_string({self.lookup_kwarg: pk}), + "selected": lookup_vals is not None and str(pk) in lookup_vals, + "query_string": changelist.get_query_string({self.lookup_kwarg: pk}), "display": mark_safe(smart_str(title)), } @@ -70,12 +79,12 @@ class CategoryFieldListFilter(ChoicesFieldListFilter): my_model_field.category_filter = True """ - def __init__(self, f, request, params, model, model_admin, field_path=None): - super().__init__(f, request, params, model, model_admin, field_path) + def __init__(self, field, *args, **kwargs): + super().__init__(field, *args, **kwargs) # Restrict results to categories which are actually in use: - related_model = f.remote_field.model - related_name = f.related_query_name() + related_model = field.remote_field.model + related_name = field.related_query_name() self.lookup_choices = sorted( ( @@ -84,20 +93,26 @@ def __init__(self, f, request, params, model, model_admin, field_path=None): _related_count=Count(related_name) ).exclude(_related_count=0) ), - key=lambda i: i[1], + key=itemgetter(1), ) - def choices(self, cl): + def choices(self, changelist): yield { "selected": self.lookup_val is None, - "query_string": cl.get_query_string({}, [self.lookup_kwarg]), + "query_string": changelist.get_query_string({}, [self.lookup_kwarg]), "display": _("All"), } + # Pre Django 5 lookup_val would be a scalar, now it can do multiple + # selections and thus is a list. Deal with that. + lookup_vals = self.lookup_val + if lookup_vals is not None and django.VERSION < (5,): + lookup_vals = [lookup_vals] + for pk, title in self.lookup_choices: yield { - "selected": pk == int(self.lookup_val or "0"), - "query_string": cl.get_query_string({self.lookup_kwarg: pk}), + "selected": lookup_vals is not None and str(pk) in lookup_vals, + "query_string": changelist.get_query_string({self.lookup_kwarg: pk}), "display": mark_safe(smart_str(title)), } From 8dd71c8e567d6a197174d6797be92f865343730d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 18 Apr 2024 10:11:15 +0200 Subject: [PATCH 1554/1590] FeinCMS v24.4.2 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 368aeeee6..a92735515 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (24, 4, 1) +VERSION = (24, 4, 2) __version__ = ".".join(map(str, VERSION)) From beead2a1fba023a6c09cd9c7bea69f3f9c3d1dd2 Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Thu, 23 May 2024 12:43:48 +0100 Subject: [PATCH 1555/1590] `Cannot combine a unique query with a non-unique query` errors that happen in admin when following a raw_id field. Fixes #716 --- feincms/admin/tree_editor.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index d1406d597..81ff2ce48 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -173,9 +173,11 @@ def get_results(self, request): # Note: Django ORM is smart enough to drop additional # clauses if the initial query set is unfiltered. This # is good. - self.queryset |= self.model._default_manager.filter( - reduce(lambda p, q: p | q, clauses) - ) + self.queryset = self.queryset.union( + self.model._default_manager.filter( + reduce(lambda p, q: p | q, clauses) + ) + ).order_by(mptt_opts.tree_id_attr, mptt_opts.left_attr) super().get_results(request) From 5833b4f63ced96c062e2a60809848a23a467bba5 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 3 Jun 2024 10:37:39 +0200 Subject: [PATCH 1556/1590] Make it build --- .readthedocs.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..b2da4c0aa --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,17 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +sphinx: + configuration: docs/conf.py +# python: +# install: +# - requirements: docs/requirements.txt +# - method: pip +# path: . From 3415dc83c9a855ec55314fb6b5d443f7cf559aff Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 3 Jun 2024 10:42:48 +0200 Subject: [PATCH 1557/1590] Remove the theme definition --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 53af7b8c9..ec2f3cd0f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -96,7 +96,7 @@ # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ['_theme'] -html_theme = "sphinx_rtd_theme" +# html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 7851f2f9425a81c92401135257be7a96dac64310 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Wed, 10 Jul 2024 11:32:09 +0200 Subject: [PATCH 1558/1590] FeinCMS v24.7.1 --- CHANGELOG.rst | 16 ++++++++++++++-- feincms/__init__.py | 2 +- .../admin/content/richtext/init_ckeditor.html | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e40d01e10..35ac8306e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,16 +6,28 @@ Change log `Next version`_ ~~~~~~~~~~~~~~~ +v24.7.1 (2024-07-10) +~~~~~~~~~~~~~~~~~~~~ + +- Fixed the read the docs build. +- Disabled the CKEditor 4 version nag. + + +v24.4.2 (2024-04-18) +~~~~~~~~~~~~~~~~~~~~ + +- Fixed the filters to work with Django 5. + v24.4.1 (2024-04-16) -~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~ - Forwarded cookies set by ``ApplicationContent`` apps to the final response. - Added support for webp image formats to the media library. v24.4.0 (2024-04-08) -~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~ - Fetched the CSRF token value from the input field instead of from the cookie. This allows making the CSRF cookie ``httponly``. Thanks to Samuel Lim for the diff --git a/feincms/__init__.py b/feincms/__init__.py index a92735515..64d9e441e 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (24, 4, 2) +VERSION = (24, 7, 1) __version__ = ".".join(map(str, VERSION)) diff --git a/feincms/templates/admin/content/richtext/init_ckeditor.html b/feincms/templates/admin/content/richtext/init_ckeditor.html index 79dbb1478..b46164608 100644 --- a/feincms/templates/admin/content/richtext/init_ckeditor.html +++ b/feincms/templates/admin/content/richtext/init_ckeditor.html @@ -6,6 +6,7 @@ +{% endblock %} + +{% block tinymce_init %} + +{% endblock %} From 0a2af362720f126eb2c12b9d50fe95e7c4426f50 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 20 Dec 2024 14:09:01 +0100 Subject: [PATCH 1570/1590] FeinCMS v24.12.1 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index a050a9cdb..89cc16357 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (24, 8, 2) +VERSION = (24, 12, 1) __version__ = ".".join(map(str, VERSION)) From aaf426fe5d96f049af8eeac289649ae142cc1330 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 20 Dec 2024 14:19:02 +0100 Subject: [PATCH 1571/1590] Toolbar configuration --- feincms/templates/admin/content/richtext/init_tinymce7.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feincms/templates/admin/content/richtext/init_tinymce7.html b/feincms/templates/admin/content/richtext/init_tinymce7.html index 7db4276e4..0cddd2afd 100644 --- a/feincms/templates/admin/content/richtext/init_tinymce7.html +++ b/feincms/templates/admin/content/richtext/init_tinymce7.html @@ -10,6 +10,10 @@ tinymce.init({ selector: `#${field.id}`, menubar: false, + statusbar: false, + plugins: "anchor autoresize link", + autoresize_bottom_margin: 20, + toolbar: "styles | bold italic sub sup | bullist numlist | anchor link unlink", }) field.dataset.initialized = true } From fbae53ba4efddebe8ed0dee808513795e9931c2f Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 20 Dec 2024 14:19:17 +0100 Subject: [PATCH 1572/1590] FeinCMS v24.12.2 --- feincms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feincms/__init__.py b/feincms/__init__.py index 89cc16357..1b8ded2e3 100644 --- a/feincms/__init__.py +++ b/feincms/__init__.py @@ -1,4 +1,4 @@ -VERSION = (24, 12, 1) +VERSION = (24, 12, 2) __version__ = ".".join(map(str, VERSION)) From 521e2881bd2c39eda5021eb24f5e740ccda04342 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 20 Dec 2024 14:24:36 +0100 Subject: [PATCH 1573/1590] Fix the state management --- feincms/templates/admin/content/richtext/init_tinymce7.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feincms/templates/admin/content/richtext/init_tinymce7.html b/feincms/templates/admin/content/richtext/init_tinymce7.html index 0cddd2afd..65d410738 100644 --- a/feincms/templates/admin/content/richtext/init_tinymce7.html +++ b/feincms/templates/admin/content/richtext/init_tinymce7.html @@ -6,7 +6,7 @@ From 2ba5668022733449d619b6615aea55c1e18eae34 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:33:01 +0000 Subject: [PATCH 1590/1590] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- feincms/admin/tree_editor.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/feincms/admin/tree_editor.py b/feincms/admin/tree_editor.py index e335eb18a..07aa1d0ab 100644 --- a/feincms/admin/tree_editor.py +++ b/feincms/admin/tree_editor.py @@ -419,22 +419,26 @@ def changelist_view(self, request, extra_context=None, *args, **kwargs): extra_context = extra_context or {} - extra_context.update({ - "tree_structure": mark_safe( - json.dumps(obj=_build_tree_structure(self.get_queryset(request)), separators=(",", ":")) - ), - - "node_levels": mark_safe( - json.dumps( - dict( - self.get_queryset(request) - .order_by() - .values_list("pk", self.model._mptt_meta.level_attr) - ), - separators=(",", ":") - ) - ) - }) + extra_context.update( + { + "tree_structure": mark_safe( + json.dumps( + obj=_build_tree_structure(self.get_queryset(request)), + separators=(",", ":"), + ) + ), + "node_levels": mark_safe( + json.dumps( + dict( + self.get_queryset(request) + .order_by() + .values_list("pk", self.model._mptt_meta.level_attr) + ), + separators=(",", ":"), + ) + ), + } + ) return super().changelist_view(request, extra_context, *args, **kwargs)